How to Moq NHibernate extension methods? - c#

I'm developing an application using NHibernate for the ORM, NUnit for unit testing and Ninject for my DI. I'm mocking the ISession like so:
var session = new Mock<ISession>();
With the regular non-mocked session objects I can query them with LINQ extension methods like this:
var result = Session.Query<MyEntity>();
But when I try to mock this with the following code...
session.Setup(s => s.Query<MyEntity>());
...I get a runtime "Not supported" exception:
Expression references a method that does not belong to the mocked object: s => s.Query<MyEntity>()
How can I mock basic queries like this in Moq/NHibernate?

Query<T>() is an extension method, that's why you can't mock it.
Although #Roger answer is the way to go, sometimes it's useful to have specific tests. You can start investigating what Query<T>() method does - either by reading the NHibernate code, or using your own tests, and set the appropriate methods on ISession.
Warning: creating such a setup will make your test very fragile, and it will break, if the internal implementation of NHibernate changes.
Anyway, you can start your investigation with:
var mockSession = new Mock<ISession>(MockBehavior.Strict); //this will make the mock to throw on each invocation which is not setup
var entities = mockSession.Object.Query<MyEntity>();
The second line above is going to throw an exception and show you which actual property/method on ISession the Query<T>() extension method tries to access, so you can set it accordingly. Keep going that way, and eventually you will have a good setup for your session so you can use it in the test.
Note: I'm not familiar with NHibernate, but I have used the above approach when I had to deal with extension methods from other libraries.

UPDATE for version 5:
In the new NHibernate versions Query<T> is part of the ISession interface, not an extension function, so it should be easy to mock.
Old answer:
I tried Sunny's suggestion and got this far but got stuck since the IQuery is cast to an NHibernate.Impl.ExpressionQueryImpl which is internal and I don't think can be extended. Just posting this to save other lost souls a couple hours.
var sessionImplMock = new Mock<NHibernate.Engine.ISessionImplementor>(MockBehavior.Strict);
var factoryMock = new Mock<NHibernate.Engine.ISessionFactoryImplementor>(MockBehavior.Strict);
var queryMock = new Mock<IQuery>(MockBehavior.Strict);//ExpressionQueryImpl
sessionImplMock.Setup(x => x.Factory).Returns(factoryMock.Object);
sessionImplMock.Setup(x => x.CreateQuery(It.IsAny<IQueryExpression>())).Returns(queryMock.Object);
sessionMock.Setup(x => x.GetSessionImplementation()).Returns(sessionImplMock.Object);

Related

Moq Setup does not work as expected in a separate class

I am using moq version 4.2 to unit test some controllers of web api 2 with EF as the ORM. Since a lot of tests need a mocked IEntityRepository<User> so I use a static method in a separate class called TestHelper to create such a fake repository so that I can just call this method in all the tests where needed. Here is the static method:
internal static IEntityRepository<User> GetSingleUserMockRepository(User user, bool noTracking = true, params Expression<Func<User, object>>[] properties)
{
var userRepository = new Mock<IEntityRepository<User>>();
if (properties.Any())
userRepository.Setup(x => x.GetSingleInclude(user.Key, noTracking, properties)).Returns(Task.FromResult(user));
else
userRepository.Setup(x => x.GetSingle(user.Key, noTracking)).Returns(Task.FromResult(user));
return userRepository.Object;
}
I am not showing other method details here because don't think they're relevant to my problem. The thing is when calling this static method in my tests and pass the returned user repository into controllers the test will fail because it cannot find the user i.e. Setup didn't work!. However, if I repeat the test implementation within my tests to create the mock repository as a local variable; everything works fine.
Namely, this doesn't work (where Devices is a navigation property on the User entity, again don't think the detail matters here) e.g. if I pass the returned userRepository into my controller the test will fail.:
var userRepository = TestHelper.GetSingleUserMockRepository(user, true, x=> x.Devices);
But this works e.g. if I just use a local variable in the test and pass the userRepository.Object into my controller everything works as expected:
var userRepository = new Mock<IEntityRepository<User>>();
userRepository.Setup(x => x.GetSingleInclude(user.Key, true, u => u.Devices)).Returns(Task.FromResult(user));
Can someone please explain why? I thought these two ways are equivalent but clearly not in practice.
This is maybe not a full answer (yet), but still to long to fit into a Stack Overflow comment.
When you do:
userRepository.Setup(x => x.GetSingleInclude(user.Key, noTracking, properties)).Returns(...);
you are saying: When GetSingleInclude is called with that user.Key and that noTracking and in particular that properties which is an array of expression trees, Moq shall return what you specify.
However, if Moq gets a call to GetSingleInclude where one or more of the arguments are not equal to the values you supplied, your setup is not relevant, and Moq returns instead the default value which is null.
(If you had used MockBehavior.Strict instead, it would have thrown an exception instead of silently just returning null, which could be more helpful for understanding the issue.)
So when are two arrays of expression trees equal? If Moq uses the default equality comparer for arrays, they are only "equal" when they are the same array instance. If Moq uses some entry-wise comparison, it will come down to whether each expression tree is equal as reference (i.e. same Expression<> instance). In any case you may have trouble.
The question is why it works in the other case. Does GetSingleInclude have special overloads for when the number of properties (expression trees) is little?
What is the result of running the code from this question?
I am saying that you may be facing the same problem as in the thread
Mocking and verifying call to method containing an Expression<Func<T,bool>> parameter.

Mocking the NHibernate JoinAlias with Moq

I have the following repository code that will return a Company object based on an ID value, searching across the standard Company table and an additional table named ExternalCompany.
public Company FindByIdJoin(long id)
{
ExternalCompany xcomp = null;
return Session.QueryOver<Company>()
.Where(p => p.ObjectId == id)
.JoinAlias(p => p.ExternalCompanies, () => xcomp, JoinType.LeftOuterJoin)
.SingleOrDefault<Company>();
}
The code returns values that I expect. However, the trouble I'm having is in writing a Moq unit test to handle the JoinAlias call.
In a simpler method, called FindById, the code is essentially the same except there is no line for JoinAlias. The unit test for this simpler method is:
[Test]
public void FindById_returns_Company_for_valid_Id()
{
// Arrange
Mock<IQueryOver<Company, Company>> mockQueryOver = new Mock<IQueryOver<Company, Company>>();
mockQueryOver.Setup(x => x.Where(It.IsAny<Expression<Func<Company, bool>>>())).Returns(mockQueryOver.Object);
mockQueryOver.Setup(x => x.SingleOrDefault()).Returns(fake_Company);
// Act
var result = _repository.FindById(fake_Company.ObjectId);
// Assert
Assert.IsNotNull(result);
mockQueryOver.VerifyAll();
}
This test works and passes without a problem (fake_Company and _repository are defined elsewhere).
The problem is trying to put a test together for the FindByIdJoin call. I have tried using an additional Setup line like this (which goes between the Where and SingleOrDefault Setup lines):
mockQueryOver.Setup(x => x.JoinAlias(It.IsAny<Expression<Func<Company>>>(), It.IsAny<Expression<Func<ExternalCompany>>>(), JoinType.LeftOuterJoin)).Returns(mockQueryOver.Object);
The system tells me that "the best overloaded method match for IQueryOver ... has some invalid arguments."
So, I tried a few other variations on the Setup, but could not find a workable pattern.
My question is: what Setup arguments will work for JoinAlias so that I can properly test the FindByIdJoin method? Thanks!
The particular overload of JoinAlias you are using is
IQueryOver<TRoot, TSubType> JoinAlias(
Expression<Func<TSubType, object>> path,
Expression<Func<object>> alias,
JoinType joinType);
So, your setup needs to match this. Based on how you setup your IQueryOver mock, the correct setup would then be
mockQueryOver.Setup(x => x.JoinAlias(
It.IsAny<Expression<Func<Company, object>>>(),
It.IsAny<Expression<Func<object>>>(),
JoinType.LeftOuterJoin))
.Returns(mockQueryOver.Object);
Shouldn't MOQ be used for behaviour tests? Such Data access tests seem to be state dependent and I think using mock objects for such a system under test is an overkill.

Moq chaining expressions results in parameter count mismatch

I'm attempting to mock a repository using Moq. I have found multiple questions with similar issues but none that I found were able to solve the issue I'm having.
So I'm using a repository that can be downloaded here. More specifically, the repository itself can be viewed here and the query extensions I'm using can be seen here.
This is what my tests setup looks like:
// A List<> of fakes.
this.containers = Builder<Container>.CreateListOfSize(10).Build();
// Here I'm trying to set up the mock object for the query.
this.containerRepoMock.Setup(p => p.
Query(It.IsAny<Expression<Func<Container, bool>>>())
.Include(It.IsAny<Expression<Func<Container, object>>>())
.Select())
.Returns((Expression<Func<Container, bool>> query, Expression<Func<Container, object>> include) =>
this.containers.AsQueryable().Where(query).Include(include));
// Tell the service to use the mock repository.
this.containerService = new ContainerService(mockUnitOfWork.Object);
This is the service method that I'm trying to test:
public ContainerDto GetContainerAndItsCategories(int containerId)
{
var entity = Repository
.Query(w => w.ContainerId == containerId)
.Include(c => c.Categories)
.Select();
var output = Mapper.EntityToDto(entity.SingleOrDefault());
return output;
}
Whenever i try to run this service method in my test using the mock repository it throws an exception "System.Reflection.TargetParameterCountException: Parameter count mismatch."
I have tried adding extra object arguments to the .Returns() method in the mock setup without any success. It always throws the same exception. From what I have been reading Moq is somewhat limited when it comes to testing expressions however i have seen examples where people are doing similar things with success.
Since the Include() and Query() methods return a IQueryFluent() instance instead of direct expressions i have tried to use the QueryFluent() class in the Moq return() method but haven't been able to do it successfully with the queryable(compile errors).
Any help would be greatly appreciated, really want to be able to test this properly using unit tests.
Edit - Similar questions that I've looked at
Moq + Unit Testing - System.Reflection.TargetParameterCountException: Parameter count mismatch
Moq Params TargetParameterCountException : Parameter count mismatch Exception
The issue is with this line:
this.containerRepoMock.Setup(p => p.
Query(It.IsAny<Expression<Func<Container, bool>>>())
.Include(It.IsAny<Expression<Func<Container, object>>>())
.Select())
You cannot (as far as my Moq knowledge goes) set up a group of methods in one Setup call. Furthermore, in this line:
.Returns((Expression<Func<Container, bool>> query, Expression<Func<Container, object>> include) =>
this.containers.AsQueryable().Where(query).Include(include));
You're telling Moq to expect (in the Setup call) a call to a single method with two parameters (query and include) and to pass those to the Returns lambda here. This is obviously not the case: you have calls to two one-parameter methods, and so Moq throws a parameter mismatch exception.
You'll need to break it down into its components and setup mocks for the return values. Also, since you want to make use of the Expression objects you'll need to save those off for use at the end. For example:
var containerRepoMock = new Mock<IRepositoryAsync<Container>>();
var queryFluentQueryMock = new Mock<IQueryFluent<Container>>();
var queryFluentIncludeMock = new Mock<IQueryFluent<Container>>();
Expression<Func<Container, bool>> query = null;
containerRepoMock.Setup(p => p.Query(It.IsAny<Expression<Func<Container, bool>>>()))
.Callback<Expression<Func<Container, bool>>>(q => query = q)
.Returns(queryFluentQueryMock.Object);
Expression<Func<Container, object>> include = null;
queryFluentQueryMock.Setup(p => p.Include(It.IsAny<Expression<Func<Container, object>>>()))
.Callback<Expression<Func<Container, object>>>(i => include = i)
.Returns(queryFluentIncludeMock.Object);
queryFluentIncludeMock.Setup(p => p.Select())
.Returns(containers.AsQueryable().Where(query).Include(include));
Please forgive any compilation errors, I didn't download the libraries you linked to to try this out

Using Mock objects with Dictionary

I just started working with Unit Testing with NMock
I one my test cases involve adding an entry in a dictionary which is then passed to the unit being tested. I define the map as:
var item = new Mock<MyClass>().Object;
var myMap = new Dictionary<MyClass, IList<MyOtherClass>>
{
{ item, completionRequirement }
};
However when I do a myMap.ContainsKey(item) inside the unit being tested it returns false.
I am able to view a proxied item in the Dictionary on inspecting it. I am guessing that I need to do something else as well on the mocked item.(Most probably define .Equals(object o)).
My question is :
How do you define the Equals(object o) for the mocked item.
Or is there a different solution to the problem altogether.
You might want to mock the dictionary as well. That is, refactor to use IDictionary<MyClass,IList<MyOtherClass>, then pass in a mocked dictionary. You can then set up expectations so that it returns mocked objects as necessary.
It's also possible that you may not need to use a mock at all in this instance. It's not possible to tell from what you've given us, but I've often found that people new to mocking can sometimes forget that you can use the real objects as well if those objects don't have cascading dependencies. For example, you don't really need to mock a class that's just a simple container. Create one and use it, instead. Just something to think about.
The approach given at http://richardashworth.blogspot.com/2011/12/using-reflection-to-create-mock-objects.html is in Java, but presents another approach to this problem using Reflection.
I like the idea of setting up a 'fake' object along the lines of what tvanfosson is suggesting.
But if you want to do it with a mocking framework, I think all you need to do is setup an expectation for what item.Object should be. In Rhino Mocks the syntax would be something like:
var knownObject = "myKey";
var mock = MockRepository.GenerateStub<IMyClass>();
mock.Stub(x=>x.Object).Return(knownObject);
That said, I have no idea what the equivalent code would be in NMocks, but it shouldn't be hard to figure it out if you're working with it (you can always ask a question on the user group).
HTH

Using typemock for chaining

I am just starting here with mocking about, and I am trying something which I think should be quite simple.
I have a class that reads Google calendar data. First, it creates a CalendarService object, then it calls Query on that object, receives a EventFeed and iterates on the Item collection of AtomEntryCollection.
I want it all to be mocked, as I don't want my tests to send any web requests around.
I tried mocking it all with
var service = MockManager.Mock<CalendarService>();
var events = MockManager.MockAll<EventFeed>();
var entries = MockManager.MockAll<AtomEntryCollection>();
service.ExpectAndReturn("Query", events.MockedInstance);
events.ExpectGet("Entries", entries.MockedInstance);
entries.ExpectGetAlways("Count", 3);
but my test fails as soon as the object returned from the service.Query() method is used. I understand that in the 5th line the entries.MockedInstance was still null, so the ExpectAndReturn recorded the null as the return value - so what am I supposed to do? How can I set the mocks to return valid mock objects, instead of nulls?
Note - I am writing a .NET 2.0 project, so I can't use the Isolator features (I think). Would that have helped me? Or maybe switching to Rhino or MOQ would make it all easier?
First, if you're using the old API, you should use MockObject, not Mock. Mock is for objects that are created later in the code under test, MockObject is for object that get created now.
But why use the old API? The best way I recommend, is write the tests in .Net 3.5, this way you get best of both worlds. In this case your setup looks like this:
var service = Isolate.Fake.Instance();
Isolate.WhenCalled(() => service.Query().Count).WillReturn(3);
var events = Isolate.Fake.Instance();
Isolate.WhenCalled(() => events.Entries.Count).WillReturn(3);
If however, you're hard pressed to use 2.0 no Lambda syntax, this is how it looks like:
var service = Isolate.Fake.Instance();
Isolate.WhenCalled(delegate { return service.Query().Count; }).WillReturn(3);
events = Isolate.Fake.Instance();
Isolate.WhenCalled(delegate { return events.Entries.Count; }).WillReturn(3);
Refer to this link on how to setup a VS2005 test to work with AAA API.

Categories