C# 如何最好地使用TDD泛型?

C# 如何最好地使用TDD泛型?,c#,unit-testing,generics,tdd,C#,Unit Testing,Generics,Tdd,假设我正在开发一个数据库应用程序,我有许多实体类,如客户、订单、产品等。我想为这些实体类开发存储库(真实的和模拟的),但我不想重复代码,所以我创建了一个基本实体类和一个包含CRUD代码的通用存储库。我的问题是,在“适当的”TDD环境中,我将如何着手开发它 我的第一反应是从一个实体(如客户)开始,并完成每个CRUD任务的TDD周期,然后当我完成大部分任务后,从另一个实体开始,依此类推。然而,如果我已经正确地设计了我的体系结构,那么在我为其他实体编写测试之前,我就可以为它们提供工作CRUD支持。我对

假设我正在开发一个数据库应用程序,我有许多实体类,如客户、订单、产品等。我想为这些实体类开发存储库(真实的和模拟的),但我不想重复代码,所以我创建了一个基本实体类和一个包含CRUD代码的通用存储库。我的问题是,在“适当的”TDD环境中,我将如何着手开发它

我的第一反应是从一个实体(如客户)开始,并完成每个CRUD任务的TDD周期,然后当我完成大部分任务后,从另一个实体开始,依此类推。然而,如果我已经正确地设计了我的体系结构,那么在我为其他实体编写测试之前,我就可以为它们提供工作CRUD支持。我对“好”TDD的印象是,您只编写失败的测试,然后针对每个测试只编写代码使其通过

对于实现的通用部分,只测试单个实体是一种糟糕的形式吗?泛型通常是如何使用TDD开发的?

没有“合适的”TDD环境。红-绿重构过程本身有许多可能的样式,TDD没有定义如何组合这些小周期以实现完全实现的系统的方法


在您的例子中,我想您可以连续实现两个存储库,认识到存在重复代码并重构到泛型,将现有测试作为测试工具。或者,从一开始就选择约束在
实体
类型上的通用存储库。只要存储库不依赖于实体特定的行为,您就可以在测试中使用
实体的伪子类。

在以前的项目中,我们做了以下工作:

  • 从一个实体开始,使用TDD为其实现一个存储库
  • 使用临时复制粘贴的测试添加另一个实体+存储库
  • 现在,您的两个实体和两个存储库之间存在重复,但绿色测试
  • 进行重构以提取实体基类,并确保所有测试都通过
  • 执行另一次重构以提取引用实体基类的通用存储库实现,并再次确保所有测试都通过
  • 您现在有了所有通过的测试和一个通用存储库,但测试中存在重复
您现在可以选择:

  • 从一个实体的测试类中删除临时复制粘贴的测试,但保留另一个实体的测试

  • 为包含泛型存储库测试的测试类提取一个超类,以便对每个实体类型运行一次测试。也就是说,如果您有一个针对
    SelectById
    的测试,那么该测试只需从公共基类继承,就可以为每个实体类型运行一次

如果使用第二种方法,您知道所有实体都有工作映射/CRUD操作,但测试套件的执行时间稍长。

我是否正确理解您有客户:实体、订单:实体等,genereic存储库iRepository在哪里T:Entity?我想我会创建几个不带基类的类,边做边做测试。然后,我将遵循Red、Green和Refactor,并介绍基类作为重构步骤。确保原始测试继续成功。弗兰克:是的,这正是我为避免代码重复所做的。Jras:这正是我所做的,然后我创建了我的基本实体类,然后从中创建了我的存储库类。我的问题是:我现在是否应该复制我的所有测试,并为使用该存储库的每个实体测试该存储库的每个实例化?只有当存储库的行为在所有实现中都不一致时,我才会使用2d方法(测试超类),即它的一些方法是抽象的或模板化的。我很少看到这种情况,通常您在基本存储库类上定义的方法基本上是实体类型无关的。这是测试不同类型存储库(如NHibernateRepository、InMemoryRepository等)的好方法。@guillaume31是的,好处在于针对每个特定实体的映射/表等运行测试。假设您在EntityB中重命名了一个属性,因此映射被破坏。如果只使用EntityA运行测试,则不会发现该问题。但是,您可能只想考虑为每个实体类型运行一个通用知识库测试的子集。谢谢各位,这很有道理,我也没有想到模板化测试类的想法。仔细考虑之后,我认为测试泛型的每个版本实际上是有意义的,特别是在实体属性为虚拟的nHibernate的情况下。虽然行为最初可能在所有存储库中都是一致的,但没有什么可以阻止稍后有人出现,并以破坏预期一致性的方式重写方法。对所有泛型类进行完整的单元测试将有助于检测由此引起的bug。