【问题标题】:Mocking complex object - testing with Moq模拟复杂对象 - 使用 Moq 进行测试
【发布时间】:2019-02-09 06:24:29
【问题描述】:

我有以下对象结构:

public class A
{
    //...
    public B b;
    //...
}

public class B
{
    //...
    public C c;
    //...
}

public class C
{
    //...
    //...
}

我想创建一些测试来编写数据库访问代码。为了实现这一点,在每次测试之前,我都会在数据库中添加一些必要的数据(我使用的是 fluent nHibernate)。

所以要测试对实体 A 执行某些操作的某些数据库方法,我需要将 A 类的对象保存到数据库中

//...
var a = new A();
session.Save(a);
//...

这会导致空引用异常,因为 B 类和 C 类的对象也是不能为空的数据库实体。

我的问题是如何通过使用 Moq 以优雅的方式避免这种异常。在我真正的问题中,对象树比这个简化的问题要复杂得多。

【问题讨论】:

  • 在您的情况下,是否有必要 100% 使用真正的数据库?从理论上讲,您能否模拟出整个“会话”对象? (就像我们目前在我的项目中所做的那样,仅使用 EF dbContext)
  • 我认为,mock session 对象就足够了,但是当涉及到这个对象树关系时,它会发生什么变化?
  • 模拟ISession 将允许您拥有A 和null B(避免保存到db = nullref exc)。检查this answer。然后,您可以设置您的 ISession 以返回您的简单 List<A>
  • 但是,实际上我想测试我的复杂数据库查询,例如:获取给定时间段内包含某些属性的所有对象
  • 好的,根据这些 cmets,我将尝试发布带有一些选项的答案

标签: c# nhibernate moq


【解决方案1】:

你有两个选择:

  1. 您违背了真正的 Db = 集成测试,这将确保您的 FK 约束、级联删除等正常工作。我建议创建一些DemoDataDbInit 类,它将执行您的初始演示数据的真实 Db 插入。对于测试,您将在第一次测试之前调用一次,保存“干净”初始化 Db 的快照(克隆),然后对于后续测试,您只需 attach this snapshot(假设您使用 MSSql),以便您的测试是独立的彼此(每个测试都有干净的 Db)。您可以在 CI 流程中重用相同的 DemoDataDbInit 类,以便在重新部署应用程序后获得一些初始虚拟数据。测试只是假设这些数据存在于数据库中。这里还考虑了Docker。 可悲的是,我忘记了一个工具的名称——它是一个非常快速的内存 Db,可作为 nuget 包使用,它与 EF 和 nHib 兼容,可用于测试——它会提供一些加速(我相信它不是 SQLite内存模式)。

  2. 你反对一个模拟。我建议您创建一些 InMemoryDb 类,这将是一个工厂,在内部使用 Moq(或其他模拟方式)为您创建一个设置 ISession

    • session.Save(entity) 会将实体添加到后台列表(模拟 IRepository
    • 它会有一些预设组和一些通常有用的标准数据

    vas session = new InMemoryDb.TwoCustomersWithThreeOrdersEach();

    • 它将所有实体公开为具有合适名称的实例属性,例如Customer1Order1,以便您可以轻松访问它们以进行其他排列或断言。
    • 如果你愿意的话,一个建设者,允许你写new InMemoryDb.TwoCustomersWithThreeOrdersEach().WithCommentOnEachOrder("my comment")等等。

您将在所有测试中重复使用此InMemoryDb。作为InMemoryDb 实现的一部分,您需要手动手动设置这些双向外键关系/导航属性 - 这样您的查询就不会崩溃。

在我当前的项目中,我们分别使用这两种方法进行集成和单元测试,并取得了成功。

我不确定这是否是您所希望的,但恐怕没有简单的方法可以“模拟自己”摆脱“真正的”nHibernate 施加的限制。要么你与真正的 DB 走完整的距离,要么你在内存中使用 mocks——同时假装你的 FK 关系是正确的。仅供参考:EF Core 有一个原生的in-memory mode

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 2022-10-13
    • 1970-01-01
    • 1970-01-01
    • 2016-12-25
    • 2013-07-08
    相关资源
    最近更新 更多