我具有以下对象结构:
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);
//...
这导致空引用异常,因为类B和C的对象也是不能为空的数据库实体。
我的问题是如何使用Moq以优雅的方式避免此类异常。在我真正的问题中,对象树比这个简化的问题要复杂得多。
答案 0 :(得分:0)
您有2个选择:
您违反了真正的Db =集成测试,这将确保您的FK约束,级联删除等工作正常。我建议创建一些DemoDataDbInit
类,该类将对初始演示数据进行真正的Db插入。对于测试,您将在第一次测试之前调用一次,保存“干净的”初始化Db的快照(克隆),然后对于后续测试,只需attach this snapshot(假设您使用MSSql),以便进行测试彼此独立(每个测试都有干净的Db)。您可以在CI流程中重用相同的DemoDataDbInit
类,以在重新部署应用程序后获得一些初始虚拟数据。测试只是假设那些数据在Db中。 Docker也在这里考虑。
遗憾的是,我忘记了一种工具的名称-它是一种非常快的内存中Db,可作为nuget软件包使用,它与EF&nHib兼容,可用于测试-它会提供一定的提速(我相信这不是SQLite在内存模式下)。
您反对模拟。我建议您创建一个InMemoryDb
类,这将是一个工厂,在内部使用Moq(或其他模拟方法)为您创建一个设置ISession
。
session.Save(entity)
会将实体添加到后台列表(模拟IRepository
)中 vas session = new InMemoryDb.TwoCustomersWithThreeOrdersEach();
Customer1Order1
)的实例属性,以便您可以轻松访问它们以进行其他安排或声明。 new InMemoryDb.TwoCustomersWithThreeOrdersEach().WithCommentOnEachOrder("my comment")
等。您将在所有测试中重用此InMemoryDb
。在实现InMemoryDb
的过程中,您需要手动设置这些双向外键关系/导航属性-以便查询不会崩溃。
在我当前的项目中,我们分别使用两种方法进行集成和单元测试,都取得了成功。
不确定这是否是您的期望,但恐怕没有简单的方法可以“摆脱” nHibernate施加的“约束”。要么与真实的DB进行全力以赴,要么在模拟中进入内存-假装FK关系是正确的。仅供参考:EF Core具有本机in-memory mode。