在 PHPUnit 中模拟接口时出现 TypeError

Getting TypeError when mocking interface in PHPUnit

我的界面如下:

interface UserRepository
{
    public function save(User $user): User;
}

我需要为此功能编写单元测试

public function action()
{
    $data = $this->request->getParsedBody() ?? [];
    $user = new User($data);
    $this->userRepository->save($user);
}

我尝试模拟用户存储库界面

$app = $this->getAppInstance();
$container = $app->getContainer();
$user = new User(['a' => 'b']);
$userRepositoryProphecy = $this->prophesize(UserRepository::class);
$userRepositoryProphecy
    ->save($user)
    ->willReturn($user)
    ->shouldBeCalledOnce();
$container->set(UserRepository::class, $userRepositoryProphecy->reveal());

但是return

TypeError : Return value of Double\UserRepository\P1::save() must be an instance of App\Domain\User\User, null returned

我使用了 slim-skeleton 和 phpunit

您的测试用例丢失,但我猜您在测试中保存的用户与您用来设置模拟的用户不同。澄清一下:

    $userA = new User(['a' => 'b']);
    $userB = new User(['c' => 'd']);

    $prophecy = $this->prophesize(UserRepository::class);
    $prophecy->save($userA)
        ->willReturn($userA)
        ->shouldBeCalledOnce();

    $repo = $prophecy->reveal();

    $repo->save($userA); // returns $userA
    $repo->save($userB); // returns null

如果您的用户存在您无法控制且不想摆脱的副作用,您可以使用回调来检查给定用户是否是您要查找的用户。

    $prophecy->save(Argument::that(fn(User $user) => $user->data === ['a' => 'b']))
        ->willReturnArgument()
        ->shouldBeCalledOnce();