提问者:小点点

php单元中的模拟接口


我有一个界面,如下所示:

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());

但返回

TypeError:Double\UserRepository\P1::Save()的返回值必须是app\domain\user\User的实例,返回null

我使用了slim-skeleton和phpunit


共1个答案

匿名用户

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

    $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();