使用 Mockery::capture 编写确定性 PHPUnit 断言
发布: (2026年3月3日 GMT+8 09:39)
2 分钟阅读
原文: Dev.to
Source: Dev.to
问题
当一个方法内部生成随机值时,它的返回值会变得不可预测,这使得在测试中编写确定性的断言变得困难。
class Hash
{
public function make($data): string
{
return hash_hmac('sha256', $data, false);
}
}
class RandomHash
{
public function __construct(public Hash $hash)
{
}
/**
* @throws \Exception
*/
public function hash(): string
{
$random = md5(random_int(1, 10));
return $this->hash->make($random);
}
}
因为 random_int 每次调用都会返回不同的值,hash() 的结果也会每次变化,所以测试无法断言一个固定的期望值。
class RandomHashTest extends TestCase
{
public function test_mockery_capturing_arguments(): void
{
$hash = new Hash();
$randomHash = new RandomHash($hash);
// 无法在此处写出确定的断言
$actual = $randomHash->hash();
}
}
解决方案
Mockery 的 捕获参数 功能可以保存传递给方法调用的参数。结合 passthru()(让原始方法正常执行),即可捕获中间的随机值,然后计算出期望的结果。
首先,将 Mockery 安装为开发依赖:
composer require --dev mockery/mockery
示例测试
use Mockery;
use PHPUnit\Framework\TestCase;
class RandomHashTest extends TestCase
{
/**
* @throws \Exception
*/
public function test_mockery_capturing_arguments(): void
{
// 为 Hash 类创建一个 spy
$hash = Mockery::spy(new Hash());
// 捕获中间的随机值;passthru 让 make() 正常运行
$hash->allows('make')
->with(Mockery::capture($random))
->passthru();
$randomHash = new RandomHash($hash);
$actual = $randomHash->hash();
// 现在 $random 已知,我们可以计算期望值
self::assertEquals((new Hash)->make($random), $actual);
}
}