我有一个服务类,其中直接创建了 TypeSaveLogRecord 对象。
class TypeSaveLogService
{
public function store(string $type, string $smId): TypeSaveLogRecord
{
$log = new TypeSaveLogRecord([
'mdm_id' => $smId,
'type' => $type
]);
$saveResult = $log->save();
if (!$saveResult) {
throw new \Exception('Failed to save type log');
}
}
}
我想为 TypeSaveLogService 创建一个测试来测试商店功能。
这是我的版本:
public function testStoreFailed()
{
$Mock = $this->createMock(TypeSaveLogRecord::class);
$Mock->method('save')->willReturn(false);
$service = new TypeSaveLogService();
$actualRes = $service->store($type, $smId);
$this->expectException('Exception');
}
但是它不起作用我无法以这种方式为 TypeSaveLogRecord 创建 Mock 。你能告诉我我做错了什么吗?不幸的是,我无法更改 TypeSaveLogService 的代码。
这不起作用的原因是您在测试中创建了 TypeSaveLogRecord 的模拟,但基本上根本没有使用它。
如果您在测试中调用
$Mock->save()
,您将意识到这个模拟(尽管不是原始类)实际上将返回 false(意思是“willReturn-Type”)。
仅仅创建一个模拟通常是不够的。您需要以某种方式对这个模拟做一些事情。在这种情况下,即使您已经创建了一个模拟,您仍然会在 TypeSaveLogService 类中创建 TypeSaveLogRecord 的普通实例。
这正是您应该将依赖项(在本例中 TypeSaveLogService 依赖于 TypeSaveLogRecord)放入构造函数中的原因。这样你就可以像这样注入你的模拟类:
class TypeSaveLogService
{
public function __construct(public TypeSaveLogRecord $log) {}
public function store(string $type, string $smId): TypeSaveLogRecord
{
$this->log->set([
'mdm_id' => $smId,
'type' => $type
]);
$saveResult = $this->log->save();
if (!$saveResult) {
throw new \Exception('Failed to save type log');
}
}
}
public function testStoreFailed()
{
$Mock = $this->createMock(TypeSaveLogRecord::class);
$Mock->method('save')->willReturn(false);
$service = new TypeSaveLogService($Mock);
$actualRes = $service->store($type, $smId);
$this->expectException('Exception');
}
如果您无法更改
TypeSaveLogService
的代码,我看不到此问题的任何解决方案,因为您将无法从“外部”那样干扰该过程。