4

我正在开发一个应用程序,使用 NHibernate 进行 ORM,NUnit 用于单元测试,Ninject 用于我的 DI。我像这样嘲笑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 中模拟这样的基本查询?

4

2 回答 2

3

Query<T>()是一种扩展方法,这就是为什么你不能模拟它。尽管@Roger 回答是可行的方法,但有时进行特定测试很有用。您可以开始研究什么Query<T>()方法起作用 - 通过阅读 NHibernate 代码或使用您自己的测试,并在 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>()方法试图访问,因此您可以相应地设置它。继续这样做,最终您将为您的会话设置一个良好的设置,以便您可以在测试中使用它。

注意:我不熟悉 NHibernate,但是当我不得不处理来自其他库的扩展方法时,我使用了上述方法。

于 2013-05-03T13:17:38.357 回答
3

版本 5 的更新:

在新的 NHibernate 版本Query<T>中,它是 ISession 接口的一部分,而不是扩展函数,所以它应该很容易模拟。

老答案:

IQuery我尝试了 Sunny 的建议并做到了这一点,但由于被强制转换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);
于 2015-07-02T18:26:22.457 回答