【问题标题】:How to Moq NHibernate extension methods?如何 Moq NHibernate 扩展方法?
【发布时间】:2013-05-03 12:03:52
【问题描述】:

我正在开发一个应用程序,将 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 中模拟这样的基本查询?

【问题讨论】:

  • 只是想了解一下:stackoverflow.com/questions/6835366/…
  • 只是一个提示 - 不要模拟 ISession。这些测试会给你带来什么好处?恕我直言 - 针对您的 NH 查询编写集成测试。对于您的单元测试,使用 DAO/repositories 等隐藏您自己的类型/接口的 ORM/NH(并改为模拟/存根/伪造这些类型)。
  • @Roger 它给您带来的好处是您不必担心实际数据库的状态。您正在单元测试,这意味着您应该只测试该方法中的代码。您的测试不应该关心是否有人删除了数据库。这不是那个方法的错。

标签: c# linq nhibernate ninject moq


【解决方案1】:

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

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

【讨论】:

  • 这是在构建测试适应度时发现依赖关系的最佳方法。 +1
  • 这并没有回答关于如何绕过它是一种扩展方法这一事实的问题,因此无法被嘲笑。
  • @krillgar,除非我遗漏了一些明显的东西,否则第一句话就是这么说的——你不能使用 moq 来模拟它(Q 用 moq 标记)。
【解决方案2】:

第 5 版更新:

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

旧答案:

我尝试了 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);

【讨论】:

    猜你喜欢
    • 2010-10-08
    • 2020-07-03
    • 2021-09-29
    • 2011-01-18
    • 2023-03-05
    • 2019-08-06
    • 1970-01-01
    相关资源
    最近更新 更多