繁体   English   中英

模拟复杂对象-使用Moq进行测试

[英]Mocking complex object - testing with Moq

我有以下对象结构:

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

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

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

我想创建一些测试来编写数据库访问代码。 为此,在每次测试之前,我都会向数据库添加一些必要的数据(我使用的是流畅的nHibernate)。

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

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

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

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

您有2个选择:

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

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

    • session.Save(entity)会将session.Save(entity)添加到后台列表(模拟的IRepository )中
    • 它将具有一些预设组以及一些经常有用的标准数据

    vas session = new InMemoryDb.TwoCustomersWithThreeOrdersEach();

    • 它将所有实体公开为具有合适名称(例如Customer1Order1实例属性,以便您可以轻松访问它们以进行其他安排或声明。
    • 如果您愿意,可以使用一个生成器,允许您编写new InMemoryDb.TwoCustomersWithThreeOrdersEach().WithCommentOnEachOrder("my comment")等。

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

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

不确定这是否是您的期望,但恐怕没有简单的方法可以“模拟” nHibernate施加的“约束”。 要么与真实的DB进行全力以赴,要么在模拟中进入内存-假装FK关系是正确的。 仅供参考:EF Core具有本机内存模式

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM