我正在使用NHibernate为ORM开发应用程序,使用NUnit进行单元测试,为我的DI开发Ninject。我这样嘲笑ISession:
var session = new Mock<ISession>();
使用常规的非模拟会话对象,我可以使用LINQ扩展方法查询它们:
var result = Session.Query<MyEntity>();
但是当我尝试使用以下代码模拟它时......
session.Setup(s => s.Query<MyEntity>());
...我得到一个运行时“不支持”例外:
Expression references a method that does not belong to the mocked object: s => s.Query<MyEntity>()
如何在Moq / NHibernate中模拟这样的基本查询?
答案 0 :(得分:3)
Query<T>()
是一种扩展方法,这就是为什么你不能嘲笑它。
虽然@Roger的答案是可行的,但有时候进行特定测试会很有用。您可以通过阅读NHibernate代码或使用自己的测试开始调查Query<T>()
方法的作用,并在ISession上设置适当的方法。
警告:创建此类设置会使您的测试非常脆弱,如果NHibernate的内部实现发生变化,它将会中断。
无论如何,您可以通过以下方式开始调查:
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>();
上面的第二行将抛出异常并显示ISession
Query<T>()
扩展方法尝试访问的{{1}}上的实际属性/方法,因此您可以相应地设置它。继续这样,最终你会有一个很好的会话设置,所以你可以在测试中使用它。
注意:我不熟悉NHibernate,但是当我不得不处理来自其他库的扩展方法时,我已经使用了上述方法。
答案 1 :(得分:1)
我尝试了Sunny的建议并且做到了这一点,但是因为IQuery
被投射到内部的NHibernate.Impl.ExpressionQueryImpl
并且我认为不能延长而被卡住了。只需发布此信息即可将其他失去的灵魂保存几个小时。
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);