Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking an NHibernate ISession with Moq

I am starting a new project with NHibernate, ASP.NET MVC 2.0 and StructureMap and using NUnit and Moq for testing. For each of my controllers I have a single public constructor into which an ISession is being injected. The application itself works just fine, but in terms of unit testing I essentially have to mock an ISession in order to test the controllers.

When I attempt to Mock the ISession with MOQ i get the following error message:

Only property accesses are supported in intermediate invocations

It appears that my problem is expecting List of users from the framework CreateQuery method but after googling the issue I am now clearer.

I have two questions:

1) Is this the WRONG way to mock dependency injection of an ISession

2) Is there a way to modify the code so that it can successfully return my list

            [Test]             public void DummyTest()             {                  var mock = new Mock<ISession>();                 var loc = new Mock<User>();                 loc.SetupGet(x => x.ID).Returns(2);                 loc.SetupGet(x => x.FirstName).Returns("John");                 loc.SetupGet(x => x.LastName).Returns("Peterson");                  var lst = new List<User> {loc.Object};                 mock.Setup(framework => framework.CreateQuery("from User").List<User>()).Returns(lst);                  var controller = new UsersController(mock.Object);                 var result = controller.Index() as ViewResult;                Assert.IsNotNull(result.ViewData);             } 

Please note, I am pretty sure I could just create a hard-coded list of users (rather than mocking an individual User and adding it to a list) but figured I'd leave the code as I have it right now.

Also, the Index action of this particular controller essentially executes the CreateQuery call mimicked above to return all users in the database. This is a contrived example - don't read anything into the details.

Thanks in advance for your help

Edit: In reply to the below comment, I am adding the stacktrace for the error. Also, all properties on the User class are virtual.

TestCase 'Beta.Tests.Unit.Controllers.UserControllerTest.Details_InValidIndex_ReturnsNotFoundView' failed: System.NotSupportedException : Only property accesses are supported in intermediate invocations on a setup. Unsupported expression framework.CreateQuery("from User"). at Moq.Mock.AutoMockPropertiesVisitor.VisitMethodCall(MethodCallExpression m) at Moq.ExpressionVisitor.Visit(Expression exp) at Moq.Mock.AutoMockPropertiesVisitor.VisitMethodCall(MethodCallExpression m) at Moq.ExpressionVisitor.Visit(Expression exp) at Moq.Mock.AutoMockPropertiesVisitor.SetupMocks(Expression expression) at Moq.Mock.GetInterceptor(LambdaExpression lambda, Mock mock) at Moq.Mock.<>c__DisplayClass122.<Setup>b__11() at Moq.PexProtector.Invoke[T](Func1 function) at Moq.Mock.Setup[T1,TResult](Mock mock, Expression1 expression) at Moq.Mock1.Setup[TResult](Expression`1 expression) Controllers\UserControllerTest.cs(29,0): at Beta.Tests.Unit.Controllers.UserControllerTest.Details_InValidIndex_ReturnsNotFoundView()

like image 960
JP. Avatar asked Dec 01 '09 20:12

JP.


People also ask

What can be mocked with Moq?

Using Moq, you can mock out dependencies and make sure that you are testing the code in isolation. Moq is a mock object framework for . NET that greatly simplifies the creation of mock objects for unit testing.

How does Moq mock work?

Mock objects allow you to mimic the behavior of classes and interfaces, letting the code in the test interact with them as if they were real. This isolates the code you're testing, ensuring that it works on its own and that no other code will make the tests fail.

Is Moq a testing framework?

The Moq framework is an open source unit testing framework that works very well with . NET code and Phil shows us how to use it.

What is Moq in NUnit testing?

Mocking is a process where dependencies are replaced by controlled replacements that simulate the behavior of the real dependencies. NUnit is a unit testing framework for . NET languages, and Moq is the most popular mocking framework for . NET.


2 Answers

Below is the solution I came up with which seems to work perfectly. Again, I am not testing NHibernate and I am not testing the database - I simply want to test the controllers which depend on NHibernate. The issue with the initial solution appears to be the fact that I was calling a Method as well as reading the List member of the session in the MOQ setup call. I broke up these calls by breaking the solution into a QueryMock and a Session Mock (create query returns an IQuery object). A transaction mock was also necessary as it is a dependency (in my case) of the session...

        [Test]         public void DummyTest()         {             var userList = new List<User>() { new User() { ID = 2, FirstName = "John", LastName = "Peterson" } };             var sessionMock = new Mock<ISession>();             var queryMock = new Mock<IQuery>();             var transactionMock = new Mock<ITransaction>();              sessionMock.SetupGet(x => x.Transaction).Returns(transactionMock.Object);             sessionMock.Setup(session => session.CreateQuery("from User")).Returns(queryMock.Object);             queryMock.Setup(x => x.List<User>()).Returns(userList);              var controller = new UsersController(sessionMock.Object);             var result = controller.Index() as ViewResult;             Assert.IsNotNull(result.ViewData);         } 
like image 182
JP. Avatar answered Oct 01 '22 01:10

JP.


Rather than mocking the Session, one might consider setting up a different Configuration for unit-tests. This unit-testing Configuration uses a fast, in-process database like SQLite or Firebird. In the fixture setup, you create a new test database completely from scratch, run the scripts to set up the tables, and create a set of initial records. In the per-test setup, you open a transaction and in the post-test teardown, you rollback the transaction to restore the database to its previous state. In a sense, you are not mocking the Session, because that gets tricky, but you are mocking the actual database.

like image 33
yfeldblum Avatar answered Oct 01 '22 03:10

yfeldblum