PHPUnit测试失败主因是断言逻辑或mock行为不匹配:assertEquals因strict模式下类型不同而失败,应改用assertSame;mock调用计数失败多因注入错误、大小写不符或参数匹配松散;expectException须在异常触发前调用;mock需显式配置expects()和willReturn()。

PHPUnit 测试不通过,八成出在断言逻辑或 mock 行为没对上——不是代码写错了,而是你写的“期望”和实际发生的“行为”根本不在一个频道上。
assertEquals 为什么总说“Expected 5, got 5”还失败?
这是最典型的“值相等但类型不同”陷阱。比如 $this->assertEquals(5, '5') 在 PHP 中默认启用松散比较(==),但 PHPUnit 7.5+ 默认启用了 strict 模式(即强制类型一致),此时整数 5 和字符串 '5' 就算数值一样也会失败。
- 查法:运行时加
--verbose看完整错误输出,注意末尾是否带(string)或(int)类型标注 - 解法:明确用
$this->assertSame(5, $result)强制类型+值一致;或用$this->assertEquals(5, $result, '', 0.0001)开启浮点容差(仅限数值) - 避坑:别依赖默认行为,所有涉及数字/布尔/空值的断言,优先选
assertSame()、assertTrue()、assertNull()等语义更严格的变体
mock 方法明明调用了,却报 “Expected 1, got 0”?
mock 的调用计数失败,往往不是没调,而是调错了对象、时机或参数。
- 确认 mock 是否被真实注入:检查被测类构造或 setter 是否真的接收了你
$this->createMock()出来的实例,而不是 new 出来的新对象 - 检查方法名拼写和大小写:PHP 是大小写敏感的,
->method('Save')和->method('save')完全不同 - 参数匹配太松:默认
with($arg)只做==比较,若传的是对象,应改用with(self::identicalTo($obj))确保是同一实例 - 调用发生在 mock 创建前:比如在
setUp()里创建 mock,但被测逻辑在__construct()中就触发了依赖方法——这时 mock 还没准备好,调用会落到原始实现或返回 null
expectException 不生效,异常直接崩掉测试?
$this->expectException() 必须在“触发异常的代码”之前调用,且中间不能有其他可能抛异常的语句干扰。
- 错例:
$this->expectException(\InvalidArgumentException::class); $result = $obj->doSomething();—— 如果doSomething()内部先调用了另一个可能抛异常的方法,就会提前中断 - 正解:把异常触发语句单独包一层,确保它是该测试中唯一可能抛出目标异常的位置
- 进阶:配合
$this->expectExceptionMessage('xxx')或$this->expectExceptionCode(404)锁定更细粒度的异常特征,避免误匹配
mock 对象返回 null,但你期望它返回具体值?
mock 默认所有方法都返回 null,必须显式配置才会返回别的东西。
- 漏了
will()链:只写了->method('getData')->willReturn('foo')是不够的,前面必须有expects()或any()声明调用预期,否则配置会被忽略 - 写反了顺序:正确是
$mock->expects($this->once())->method('foo')->willReturn('bar');如果把expects()放在willReturn()后面,PHPUnit 会静默忽略 - 返回值类型不匹配:比如方法声明返回
string,但你willReturn(123),某些严格模式下会触发类型警告甚至失败
最难 debug 的永远不是语法错误,而是“你以为 mock 在那儿,其实它根本没接收到调用”——多打一行 var_dump(get_class($dependency)) 确认注入对象的真实类型,比反复改断言有用得多。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











