如果您想同时使用 TDD(或任何其他具有高测试覆盖率的测试方法)和 EF,您必须编写集成或端到端测试。这里的问题是,任何模拟上下文或存储库的方法都只会创建可以测试您的上层逻辑(使用这些模拟)而不是您的应用程序的测试。
简单示例:
让我们定义通用存储库:
public interface IGenericRepository<TEntity>
{
IQueryable<TEntity> GetQuery();
...
}
让我们写一些业务方法:
public IEnumerable<MyEntity> DoSomethingImportant()
{
var data = MyEntityRepo.GetQuery().Select((e, i) => e);
...
}
现在,如果您模拟存储库,您将使用 Linq-To-Objects 并且您将获得绿色测试,但如果您使用 Linq-To-Entities 运行应用程序,您将收到异常,因为不支持使用索引选择重载L2E。
这是一个简单的例子,但是在查询中使用方法和其他常见错误也会发生同样的情况。此外,这也会影响通常在存储库中公开的添加、更新、删除等方法。如果您不编写将精确模拟 EF 上下文行为和引用完整性的模拟,您将不会测试您的实现。
故事的另一部分是延迟加载问题,通过针对模拟的单元测试也很难检测到。
因此,您还应该引入集成或端到端测试,这些测试将适用于使用真实 EF 上下文和 L2E 的真实数据库。顺便提一句。需要使用端到端测试才能正确使用 TDD。对于在 ASP.NET MVC 中编写端到端测试,您可以 WatiN 并且可能还 SpecFlow 用于 BDD,但这确实会增加很多工作,但您将真正测试您的应用程序。如果您想了解更多关于 TDD 的信息,我推荐 this book(唯一的缺点是示例是用 Java 编写的)。
如果您不使用通用存储库并且将查询隐藏在某个不会公开IQueryable 但直接返回数据的类中,则集成测试是有意义的。
例子:
public interface IMyEntityRepository
{
MyEntity GetById(int id);
MyEntity GetByName(string name);
}
现在您可以编写集成测试来测试此存储库的实现,因为查询隐藏在此类中并且不会暴露给上层。但是这种类型的存储库在某种程度上被认为是与存储过程一起使用的旧实现。使用此实现,您将失去很多 ORM 功能,或者您将不得不做很多额外的工作 - 例如添加 specification pattern 以便能够在上层定义查询。
在 ASP.NET MVC 中,您可以使用控制器级别的集成测试部分替换端到端测试。
根据评论编辑:
我并不是说您需要单元测试、集成测试和端到端测试。我说制作经过测试的应用程序需要更多的努力。所需测试的数量和类型取决于您的应用程序的复杂性、应用程序的预期未来、您的技能和其他团队成员的技能。
完全无需测试就可以创建小型直截了当的项目(好吧,这不是一个好主意,但我们都这样做了,最后它奏效了)但是一旦项目通过了一些门槛,您就会发现引入新功能或维护该项目非常困难,因为您永远无法确定它是否会破坏已经起作用的东西——这就是所谓的回归。对回归的最佳防御是一套好的自动化测试。
- 单元测试帮助您测试方法。理想情况下,此类测试应涵盖方法中的所有执行路径。这些测试应该非常简短且易于编写 - 复杂的部分可以是设置依赖项(模拟,faktes,存根)。
- 集成测试可帮助您测试跨多个层的功能,通常跨多个进程(应用程序、数据库)。您不需要为所有事情都拥有它们,更多的是经验来选择它们有帮助的地方。
- 端到端测试类似于用例/用户故事/功能的验证。它们应该涵盖整个需求流程。
不需要多次测试一个功能 - 如果您知道该功能是在端到端测试中测试的,那么您就不需要为相同的代码编写集成测试。此外,如果您知道该方法只有集成测试涵盖的单一执行路径,则无需为其编写单元测试。这在 TDD 方法中效果更好,您从大型测试(端到端或集成)开始并深入到单元测试。
根据您的开发方法,您不必从一开始就使用多种类型的测试,但您可以稍后再介绍它们,因为您的应用程序会变得更加复杂。例外情况是 TDD/BDD,您应该在编写单行其他代码之前至少开始使用端到端测试和单元测试。
所以你问错问题了。问题不是什么更简单?问题是最终什么会对您有所帮助,什么复杂性适合您的应用程序?如果您想轻松地对应用程序和业务逻辑进行单元测试,您应该将 EF 代码包装到其他一些可以模拟的类中。但同时您必须引入其他类型的测试以确保 EF 代码正常工作。
我不能告诉你哪种方法适合你的环境/项目/团队/等等。但我可以解释一下我过去项目的例子:
我和两个同事一起在这个项目上工作了大约 5-6 个月。该项目基于 ASP.NET MVC 2 + jQuery + EFv4 并以增量和迭代的方式开发。它有很多复杂的业务逻辑和很多复杂的数据库查询。我们从通用存储库和高代码覆盖率开始,通过单元测试+集成测试来验证映射(用于插入、删除、更新和选择实体的简单测试)。几个月后,我们发现我们的方法不起作用。我们有超过 1200 个单元测试,代码覆盖率大约 60%(这不是很好)和很多回归问题。更改 EF 模型中的任何内容都可能在数周未触及的部分中引入意外问题。我们发现我们缺少应用程序逻辑的集成测试或端到端测试。在另一个项目上工作的并行团队也得出了相同的结论,并且将使用集成测试作为新项目的建议。