【问题标题】:Is it wrong to favour integration testing over unit testing?倾向于集成测试而不是单元测试是错误的吗?
【发布时间】:2012-07-24 10:49:40
【问题描述】:

我们正在运行一个项目,在该项目上我们在开发开始很久之后就开始采用测试驱动设计。

我们有单元测试和集成测试。集成测试在真实数据库上运行,在运行测试之前以已知状态初始化。

当我们编写测试时,我们开始注意到,甚至对于可以以“标准方式”、隔离和模拟对象进行测试的类,它实际上变得更快、更清晰(阅读:更短、更容易理解的代码) 只使用真实的对象/服务直接与数据库对话,而不是使用复杂的模拟对象设置来混淆测试类。

这种方法有什么问题吗?

【问题讨论】:

    标签: unit-testing mocking integration-testing


    【解决方案1】:

    这并没有错,完全没有。相反,根据我的经验,我会说支持单元测试是错误的。您的团队对测试“变得更快、更干净”的看法与我多年前和从那时起的看法相同。

    我什至建议您完全放弃单元测试,并继续投资于集成测试。我这样说是作为一个使用非常复杂的模拟 API 开发测试库的人,他多年来一直为孤立的单元测试提供怀疑的好处,然后最终得出集成测试的结论(在编写了许多这两种测试之后) 所以好多了。

    一个更正,不过:单元测试“隔离和模拟对象”是不是的“标准方式”。您可能知道,Kent Beck 是"father" of TDD 和 JUnit 的发明者。但是你猜怎么着,Kent 在他的 TDD 单元测试中根本没有使用模拟。严格来说,由发明 TDD 的人编写的“单元”测试更接近于集成测试,因为它们没有努力将被测单元与其依赖项隔离开来。 (这是对单元测试的常见误解。有关准确定义,请参阅 Martin Fowler 的 this article。)

    【讨论】:

    • 感谢您分享您的经验,您提到的 Fowler 链接很有趣,尤其是关于 solitary 或 socialable 测试的部分!
    【解决方案2】:

    如果您使用的是真实对象/服务,那么您不知道测试失败的原因。例如。您更改了服务实现中的某些内容,或重命名了数据库字段,或者您的网络出现故障 - 您有 50 个失败的“单元”测试。在这种情况下,您也不能进行测试驱动开发,因为您正在测试的类所需的依赖项应该在您编写测试之前实现。你能预见到你的服务的消费者将需要哪个 API 吗?这将导致可用的 API 和根本不使用的代码(参数、方法等)减少。

    如果您的测试花费大量精力来安排模拟,那么:

    • 测试应该简短而简单
    • 不要验证其他测试已经验证过的内容
    • 依赖项应该易于交互
    • 尝试为您的类(依赖项和 sut)遵循单一职责原则
    • 尝试关注Tell Don't Ask Principle - 不要问很多依赖问题,告诉它你想要什么

    【讨论】:

    • 感谢您对此的意见。 更快,我的意思是写得更快,显然不是执行得更快,很抱歉造成混乱。
    • @Benjamin 如果您必须为测试做大量安排,也许您一次要测试很多,或者有时间重构您的代码 - 而不是与依赖关系聊天,只问一个问题:)
    • 虽然不大,但只是为一些Service或Repository设置一个mock对象,相对于集成测试中的两行代码而言,可以轻松执行数十行代码!可读性也胜出...
    • 用 JMock(和其他)模拟一行:Service service = context.mock(Service.class); // 通过一次主要测试一件事来隔离你的测试,那么就没有太多的设置要做 - 如果很难测试它会告诉你一些关于你的设计的事情
    • 我使用的是 PHPUnit,看起来有点麻烦,但我明白你的意思,谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-20
    • 2021-12-19
    • 2014-09-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-13
    • 2011-05-15
    相关资源
    最近更新 更多