9. 测试替身
最后更新于:2022-04-01 03:45:47
# 第 9 章 测试替身
Gerard Meszaros 在 [[Meszaros2007]](# "xUnit Test Patterns: Refactoring Test Code") 中介绍了测试替身的概念:
> 有时候对被测系统(SUT)进行测试是很困难的,因为它依赖于其他无法在测试环境中使用的组件。这有可能是因为这些组件不可用,它们不会返回测试所需要的结果,或者执行它们会有不良副作用。在其他情况下,我们的测试策略要求对被测系统的内部行为有更多控制或更多可见性。
> 如果在编写测试时无法使用(或选择不使用)实际的依赖组件(DOC),可以用测试替身来代替。测试替身不需要和真正的依赖组件有完全一样的的行为方式;他只需要提供和真正的组件同样的 API 即可,这样被测系统就会以为它是真正的组件!
> --Gerard Meszaros
PHPUnit 提供的 `getMockBuilder($type)` 方法可以在测试中用来自动生成对象,此对象可以充当任意指定原版类型(接口或类名)的测试替身。在任何预期或要求使用原版类的实例对象的上下文中都可以使用这个测试替身对象来代替。
在默认情况下,原版类的所有方法都会被替换为只会返回 `null` 的伪实现(其中不会调用原版方法)。使用诸如 `will($this->returnValue())` 之类的方法可以对这些伪实现在被调用时应当返回什么值做出配置。
### 局限性:final、private、与 static 方法
请注意,`final`、`private` 和 `static` 方法无法对其进行上桩(stub)或模仿(mock)。PHPUnit 的测试替身功能将会忽略它们,并维持它们的原始行为。
### 警告
请关注一下这个事实:参数管理方式已经修改过了。在之前的实现中,将会克隆对象的所有参数。这样就无法检查传递给方法的是否是同一个对象。[Example 9.15, “测试某个方法将会被调用一次,并且以某个特定对象作为参数。”](# "Example 9.15. 测试某个方法将会被调用一次,并且以某个特定对象作为参数。") 展示了新的实现方式在什么情况下会非常有用。[Example 9.16, “创建仿件对象时启用参数克隆”](# "Example 9.16. 创建仿件对象时启用参数克隆")展示了如何切换回之前的行为方式。