使用Moq模拟NHibernate ISession

JP.*_*JP. 25 .net c# nhibernate unit-testing moq

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

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

中间调用仅支持属性访问

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

我有两个问题:

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

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

            [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);
            }
Run Code Online (Sandbox Code Playgroud)

请注意,我很确定我可以创建一个硬编码的用户列表(而不是模拟单个用户并将其添加到列表中),但我想我现在已经保留了代码.

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

在此先感谢您的帮助

编辑:在回复以下评论时,我正在添加错误的堆栈跟踪.此外,User类上的所有属性都是虚拟的.

TestCase'Beta.Tests.Unit.Controllers.UserControllerTest.Details_InValidIndex_ReturnsNotFoundView'失败:System.NotSupportedException:在设置的中间调用中仅支持属性访问.不支持的表达式framework.CreateQuery("来自用户").位于Moq.Mock.AutoMockPropertiesVisitor的Moq.ExpressionVisitor.Visit(表达式exp)Moq.Mock.AutoMockPropertiesVisitor.VisitMethodCall(MethodCallExpression m)的Moq.Exkression.Vatitor上的Moq.Mock.AutoMockPropertiesVisitor.VisitMethodCall(MethodCallExpression m)中的Moq.Mock.AutoMockPropertiesVisitor.VisitMethodCall(MethodCallExpression m) Moq.Mock上的Moq.Mock.GetInterceptor(LambdaExpression lambda,Mock mock)的.SetupMocks(表达式表达式).<> c__DisplayClass12 2.<Setup>b__11() at Moq.PexProtector.Invoke[T](Func1函数)在Moq.Mock.Setup [T1,TResult](模拟模拟,表达式1 expression) at Moq.Mock1.Setup [ TResult](表达式`1表达式)Controllers\UserControllerTest.cs(29,0):在Beta.Tests.Unit.Controllers.UserControllerTest.Details_InValidIndex_ReturnsNotFoundView()

JP.*_*JP. 22

以下是我提出的解决方案似乎完美无缺.同样,我没有测试NHibernate而我没有测试数据库 - 我只是想测试依赖于NHibernate的控制器.初始解决方案的问题似乎是我在MOQ设置调用中调用Method以及读取会话的List成员这一事实.我通过将解决方案分解为QueryMock和Session Mock(创建查询返回IQuery对象)来解决这些调用.事务模拟也是必要的,因为它是会话的依赖(在我的例子中)...

        [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);
        }
Run Code Online (Sandbox Code Playgroud)


yfe*_*lum 18

Session可以考虑Configuration为单元测试设置不同的,而不是模仿.此单元测试Configuration使用快速的进程内数据库,如SQLite或Firebird.在夹具设置中,您可以从头开始创建新的测试数据库,运行脚本来设置表,并创建一组初始记录.在每次测试设置中,您打开一个事务,并在后测试拆解中,回滚事务以将数据库还原到其先前的状态.从某种意义上说,你并不是在嘲笑Session,因为这很棘手,但你在嘲笑实际的数据库.

  • 除此之外,当您执行此操作时,您没有运行单元测试,而是在运行与数据库的集成测试.然后,您已经失去了编写单元测试的任何好处. (5认同)
  • 不幸的是,当涉及到相关对象,延迟加载,缓存以及NHibernate所做的所有其他事情时,NHibernate`Assse`非常复杂.所以我会跳过尝试模拟它,而是尝试模拟数据库.NHibernate很容易从映射为任何给定的数据库系统生成模式创建脚本,然后执行该脚本以在fixture-setup上使用模式创建一个空数据库.根据我自己对NHibernate的经验以及观察像Rails这样的框架,这基本上是唯一的出路. (4认同)