应根据测试框架选择:用 phpunit 则装 phpspec/prophecy,用 phpspec 则装 phpspec/phpspec;前者提供 prophet 类供手动 mock,后者自带 cli 命令和自动依赖;勿同时安装,避免 autoloader 冲突。

composer require 该装 phpspec/prophecy 还是 phpspec/phpspec?
取决于你用什么测试框架——不是看名字里有没有“mock”,而是看测试入口在哪。
- 用
PHPUnit写传统单元测试,需要在测试里手动创建 mock 对象(比如new Prophet()),就装phpspec/prophecy - 用
phpspec写 spec 文件、跑phpspec run或phpspec describe,就装phpspec/phpspec,它会自动拉取phpspec/prophecy作为依赖 - 别两个都
require:容易触发Class 'Prophecy\Prophet' not found,因为 autoloader 路径冲突
安装后为什么运行 prophecy 命令报 command not found?
Prophecy 没有 CLI 入口,它不是独立工具,只是模拟引擎。
-
composer require --dev phpspec/prophecy成功后,你只能在 PHP 代码里用Prophecy\Prophet类 -
prophecy命令根本不存在,这不是 bug,是设计如此 - 想跑命令行测试?那是
phpspec的事,装phpspec/phpspec后才有phpspec命令
new Prophet() 之后调 getPromise() 报错,怎么写才对?
你几乎不需要手动 new Prophet(),更不该对 ObjectProphecy 实例调 getPromise()。
- 正确链路是:
$prophet = new \Prophecy\Prophet(); $user = $prophet->prophesize(User::class); -
$user是ObjectProphecy实例,它没有getPromise()方法 - 要设返回值:用
$user->getName()->willReturn('Alice'),不是->getPromise() - 要拿到真实代理对象:调
$user->reveal(),不是getPromise()
为什么 setUp() 里 new Prophet() 后,tearDown() 必须 prophesize()->unprophesize()?
不清理会导致预言对象残留,影响后续测试——尤其在共享 $prophet 实例时。
-
Prophet维护内部预言注册表,不手动清理可能引发Method x was not called误报 - 推荐写法:
protected function tearDown(): void { $this->prophet->checkPredictions(); parent::tearDown(); } - 如果没显式调
checkPredictions(),某些断言(如shouldHaveBeenCalled())可能静默失败 - 注意:
unprophesize()不是必须的,checkPredictions()才是验证关键
ObjectProphecy 实例的行为定义;最容易被忽略的是预言生命周期管理——它不像 Mockery 那样自动清理,漏掉 checkPredictions() 就等于关掉了断言开关。











