如何使用 phpunit 正确创建类依赖的模拟?

问题描述 投票:0回答:1

我有一个服务类,其中直接创建了 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 的代码。

php phpunit
1个回答
0
投票

这不起作用的原因是您在测试中创建了 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
的代码,我看不到此问题的任何解决方案,因为您将无法从“外部”那样干扰该过程。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.