单元测试&使用级联CRUD操作的Fake Repository实现

时间:2010-05-20 21:29:07

标签: .net unit-testing persistence repository domain-driven-design

我在编写使用假存储库的集成测试时遇到了麻烦,

例如:假设我有一个教室实体,它聚集了学生......

var classroom = new Classroom();
classroom.Students.Add(new Student("Adam"));

_fakeRepository.Save(classroom);

_fakeRepostiory.GetAll<Student>().Where((student) => student.Name == "Adam")); 
// This query will return null...

当我使用真正的存储库实现(基于NHibernate)时,上面的代码可以工作(因为保存操作会级联到前一行添加的学生),

您知道支持此行为的任何虚假存储库实现吗? 关于如何自己实施的想法?

或者你有什么其他建议可以帮助我避免这个问题吗?

提前致谢, 埃里克。

3 个答案:

答案 0 :(得分:2)

如果您正在编写“集成测试”,因为您的问题正文表明,您不会使用虚假实现 - 使用真实的东西。

如果您正在编写单元测试,正如您的问题标题所示,您不会关心该操作是否级联,因为这不是课堂课程的关注 - 您关心的只是{{1}在类作为依赖项给出的任何存储库中调用。

如果您正在围绕NHibernate执行级联操作的能力编写单元测试,那么这些测试已经编写完成,并且没有证明课堂课程。

编辑以回应评论:

单元测试用于测试功能的各个“单元”,独立于任何其他类或服务 - 在这种情况下,您使用伪造用于其他类,以确保它们确实完成并且仅限于此类所需的内容。集成测试用于测试多个类和/或子系统之间的交互(如数据库访问,ORM等)。在这种情况下,似乎你想测试级联保存/更新,但这是NHibernate的责任,不是吗?

但是,假设您有一个使用Save()保存classroom的类,并且它将该操作包装在IRepository<Classroom>块中,并且您希望在{{{{}}时对其进行单元测试1}}抛出try…catch,错误计数属性,IRepository<Classroom>递增。在这里你需要你的存储库的虚假实现,这就是像RhinoMocks,nMock,Moq或TypeMock Isolator这样的模拟框架发挥作用 - 这些可以为你生成假的,使用接口,抽象类或已声明其公共方法和属性的类RepositoryWriteFailureException

我可能会像这样写一个测试的主体(将其视为伪代码):

ErrorCount

请注意我们如何测试virtual.类或者您正在测试的任何内容的行为,甚至无需实现存储库。

答案 1 :(得分:1)

由于它是集成测试,我建议您使用真实的存储库,而不仅仅是假存储库。

一个好的解决方案是创建一个单独的数据库用于测试目的,并在测试项目的配置文件中将NHibernate的hbm2ddl.auto属性设置为create,这样每次都会重新创建数据库,所以你不必担心这个问题。

我将此用于测试目的。我使用FluentNHibernate的自动映射器和自定义约定。如果您想使用更轻的SQL Server进行测试,您可能还想使用SQLite (我使用SQL Server以这种方式对我的存储库进行单元测试。)

如果您希望保留已输入的数据,也可以将其设置为update,如果您可以手动创建测试数据库,则根本不应设置它

答案 2 :(得分:0)

+1,如果测试不使用真实的东西(即不测试与RDBMS的集成),则不要将其称为“集成测试”。

如果你想要级联和NHibernate的所有其他优点«单元测试»的速度,我发现使用内存数据库(SQLite)非常有用。