为什么减少嘲笑可以改善每个人的测试体验

关于使用模拟进行单元测试,社区中存在一些困惑。 模拟正在创建模拟真实对象行为的对象。 我个人默认情况下不模拟类依赖关系,而是使用真实对象并通过依赖关系注入来测试双打。

尽管这种方法取得了成功,但许多开发人员仍然担心所产生的测试只是某种组件或集成测试,而不是真正的单元测试。

没有模拟的测试仍然是真实的单元测试吗? 是!

这些明显矛盾的方法被称为单元测试的经典和嘲笑风格:

经典的TDD风格是在可能的情况下使用真实的对象,而在使用真实的对象时则使用双重对象。 因此,传统的TDDer将使用一个真实的仓库和一个双重的邮件服务。 双重类型并没有那么重要。

但是,模拟派TDD练习者将始终对任何具有有趣行为的对象使用模拟。 在这种情况下,对于仓库和邮件服务。

马丁·福勒

有时,模拟和测试双打对于编写测试非常必要,但是创建和维护模拟可能是一项耗时的工作。 如果您关心生产力,则应考虑避免它们的广泛使用,而更喜欢使用实际对象。 根据我的经验,它们没有害处-恰恰相反:您可以立即看到真实对象之间如何交互,而不必等待功能测试。 确实,过度模拟的需求可能表明不良的软件设计。

我的TestTools库为PHPUnit提供了服务容器和自初始化固定装置

在实践中发现断行不是问题

当发现代码断行时,模拟主义者的风格可能会更精确一些,因为所有类都经过完全隔离的测试。 实际上,经典的单元测试还将为您提供一个堆栈跟踪,将您指向正确的代码行:

我们不难发现实际故障,即使它导致相邻测试失败。 因此,我们认为隔离实际上不是问题。

马丁·福勒

在最坏的情况下,如果只有一个类或函数被破坏,则将有多个测试案例失败。 这将为您提供有关该问题的更多信息,并允许轻松查找和修复受影响的代码。

将单元不视为孤立的类,而是某种功能

好的类抽象出它们的依赖关系和内部工作原理(封装),因此您在测试中不必关心或担心它们。 唯一的例外是数据库和其他外部服务,应使用测试双精度来代替,例如自我初始化的伪造品。 每次都返回相同数据的灯具非常好,因为单元测试不喜欢定义状态。 如果必须测试状态,请改用用户界面或API的功能测试。