使用 Moq 模拟 NHibernate ISession [英] Mocking an NHibernate ISession with Moq

查看:14
本文介绍了使用 Moq 模拟 NHibernate ISession的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 NHibernate、ASP.NET MVC 2.0 和 StructureMap 开始一个新项目,并使用 NUnit 和 Moq 进行测试.对于我的每个控制器,我都有一个公共构造函数,ISession 被注入其中.应用程序本身工作得很好,但就单元测试而言,我基本上必须模拟 ISession 以测试控制器.

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.

当我尝试使用 MOQ 模拟 ISession 时,我收到以下错误消息:

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

仅支持属性访问在中间调用中

Only property accesses are supported in intermediate invocations

看来我的问题是期望来自框架 CreateQuery 方法的用户列表,但在谷歌搜索问题后,我现在更清楚了.

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

我有两个问题:

1) 这是模拟 ISession 依赖注入的错误方式吗

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

2) 有没有办法修改代码,让它成功返回我的列表

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.

此外,这个特定控制器的 Index 操作本质上执行上面模拟的 CreateQuery 调用以返回数据库中的所有用户.这是一个人为的例子 - 不要阅读任何细节.

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.

预先感谢您的帮助

为了回复下面的评论,我正在添加错误的堆栈跟踪.此外,User 类的所有属性都是虚拟的.

测试用例'Beta.Tests.Unit.Controllers.UserControllerTest.Details_InValidIndex_ReturnsNotFoundView'失败: System.NotSupportedException :仅支持属性访问在一个中间调用设置.不支持的表达framework.CreateQuery("来自用户").在Moq.Mock.AutoMockPropertiesVisitor.VisitMethodCall(MethodCallExpression)m) 在Moq.ExpressionVisitor.Visit(表达式exp) 在Moq.Mock.AutoMockPropertiesVisitor.VisitMethodCall(MethodCallExpression)m) 在Moq.ExpressionVisitor.Visit(表达式exp) 在Moq.Mock.AutoMockPropertiesVisitor.SetupMocks(表达式表达式)在Moq.Mock.GetInterceptor(LambdaExpression)lambda,模拟模拟)在Moq.Mock.<>c__DisplayClass122.b__11()在 Moq.PexProtector.Invoke[T](Func1功能)在Moq.Mock.Setup[T1,TResult](Mock mock,表达式<代码>1 表达式) 在Moq.Mock1.Setup[TResult](Expression`1表达)控制器UserControllerTest.cs(29,0):在Beta.Tests.Unit.Controllers.UserControllerTest.Details_InValidIndex_ReturnsNotFoundView()

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) ControllersUserControllerTest.cs(29,0): at Beta.Tests.Unit.Controllers.UserControllerTest.Details_InValidIndex_ReturnsNotFoundView()

推荐答案

以下是我想出的解决方案,看起来效果很好.同样,我不是在测试 NHibernate,也不是在测试数据库——我只是想测试依赖于 NHibernate 的控制器.初始解决方案的问题似乎是我正在调用方法以及在 MOQ 设置调用中读取会话的 List 成员.我通过将解决方案分解为 QueryMock 和 Session Mock(创建查询返回一个 IQuery 对象)来分解这些调用.事务模拟也是必要的,因为它是会话的依赖项(在我的情况下)...

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);
        }

这篇关于使用 Moq 模拟 NHibernate ISession的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆