我们正在运行一个项目,我们在开发开始很久之后就开始采用测试驱动设计。
我们有单元测试和集成测试。集成测试在真实数据库上运行,在运行测试之前以已知状态初始化。
当我们编写测试时,我们开始注意到甚至可以以“标准方式”测试的类,隔离和模拟对象,它实际上变得更快,更简洁(阅读:更短且更容易理解的代码)使用真实的对象/服务直接与数据库对话,而不是使用复杂的模拟对象设置来混乱测试类。
这种方法有什么问题吗?
我们正在运行一个项目,我们在开发开始很久之后就开始采用测试驱动设计。
我们有单元测试和集成测试。集成测试在真实数据库上运行,在运行测试之前以已知状态初始化。
当我们编写测试时,我们开始注意到甚至可以以“标准方式”测试的类,隔离和模拟对象,它实际上变得更快,更简洁(阅读:更短且更容易理解的代码)使用真实的对象/服务直接与数据库对话,而不是使用复杂的模拟对象设置来混乱测试类。
这种方法有什么问题吗?
一点问题都没有。相反,根据我的经验,我会说支持单元测试是错误的。你的团队对测试“变得更快、更干净”的看法与我多年前和从那时起的看法相同。
我什至建议您完全放弃单元测试,并继续投资于集成测试。我这样说是作为一个使用非常复杂的模拟 API 开发测试库的人,他多年来一直为孤立的单元测试提供怀疑的好处,然后最终得出集成测试的结论(在编写了许多这两种测试之后)好多了。
不过,一项更正:“孤立地和使用模拟对象”的单元测试不是“标准方式”。您可能知道,Kent Beck 是TDD 的“父亲”,也是 JUnit 的发明者。但是你猜怎么着,Kent 在他的 TDD 单元测试中根本没有使用模拟。严格来说,由发明 TDD 的人编写的“单元”测试更接近于集成测试,因为它们没有努力将被测单元与其依赖项隔离开来。(这是对单元测试的常见误解。有关准确定义,请参阅Martin Fowler 的这篇文章。)
如果您使用的是真实的对象/服务,那么您不知道为什么您的测试失败了。例如,您在服务实现中更改了某些内容,或者重命名了数据库字段,或者您的网络出现故障 - 您有 50 个失败的“单元”测试。在这种情况下,您也不能进行测试驱动开发,因为您正在测试的类所需的依赖项应该在您编写测试之前实现。你能预见到你的服务的消费者将需要哪个 API 吗?这将导致根本不使用的 API 和代码(参数、方法等)的可用性降低。
如果您的测试花费大量精力来安排模拟,那么: