1

在阅读了相当多的文档后,我想出了这个函数来测试服务方法findAllUsers。我首先创建存储库的存根,然后告诉相关方法findAllusers返回什么(是的,它们在 repo 和服务中具有相同的名称),然后创建一个我想UserService.php用 repo 存根和空实例测试的类的实例。

public function testFindAllUsers()
{
    $userProvider = new UserProvider();
    $users = $userProvider->getSampleUsers();

    $repoStub = $this->createMock(UserRepository::class);
    $repoStub->method('findAllUsers')->willReturn($users);

    // Here I want to instantiate UserService with my custom repo stub but then I have to add the other dependencies as well
    // They are only empty instances and they don't matter in this test case so it works but is that correct? What should / could I do else?
    $service = new UserService($repoStub, new UserValidation(new Logger(), $repoStub), new Logger());
    $this->assertEquals($users, $service->findAllUsers());
}// Test passes

类的构造函数UserService.php

public function __construct(UserRepository $userRepository, UserValidation $userValidation,LoggerInterface $logger){ ... } 

UserValidation.php

public function __construct(LoggerInterface $logger, UserRepository $userRepository){ ... }

我觉得给类提供空实例并不是很优雅。有没有更清洁的方法?我想我想要的是创建一个UserService仅提供相关依赖项(模拟UserRepository实例)的实例,并让其余部分由 di 容器自动装配,php-di这有意义吗?我听说过创建一个用于测试的容器,该容器返回手动创建的具有默认返回值的假类,因为它无论如何都用于稍后的集成测试。我很想看到一些例子和变体。

我对自动化测试非常陌生,因此欢迎对此功能提出任何批评,即使它与问题没有直接关系。

编辑

在阅读了评论和答案之后,我认为我可以想象的理想功能是在容器中注册UserService类,该容器使用所需的自定义依赖项(在我的情况下是模拟UserRepository)和(对于最少的开销)进行实例化其他依赖项的空模拟,不仅用自定义模拟替换存储库,还让自动装配功能注入真正的依赖项。但也许我在这里错了,我不知道注入真正的依赖项是否更慢或更多开销

为了实现这一点,尽管在容器中注册新依赖项的函数必须以某种方式检测给定的参数(UserRepository如果有多个,则包含或数组)和所需的缺失依赖项(UserValidationand Logger)并模拟它们并最终创建UserServicewith cutom的实例UserRepository和被嘲笑的UserValidationand Logger

这是我的编程和 PHP 知识有限的地方,因为我不知道一种干净的编程方式。可能我不是第一个这样做的人,无论如何它是非常反模式的,但是如果我知道你对这个想法的看法以及为什么这可能是一个坏主意以及如何做到这一点,我会很有趣。

4

1 回答 1

1

您可以创建一个模拟存储库并将其设置到容器中。其余的将通过自动装配解决。确保每次测试都重新加载您的容器。

例子

要将模拟实例设置到容器中,请将此方法添加到特征或基类中:

use PHPUnit\Framework\MockObject\MockObject;

// ...

protected function mock(string $class): MockObject
{
    $mock = $this->getMockBuilder($class)
        ->disableOriginalConstructor()
        ->getMock();

    $this->container->set($class, $mock);

    return $mock;
}

测试使用

public function testFindAllUsers()
{
    // Data provider
    $userProvider = new UserProvider();
    $users = $userProvider->getSampleUsers();

    // Mock the required repositories
    $this->mock(UserRepository::class)
      ->method('findAllUsers')
      ->willReturn($users);

    // Instantiate UserService
    $service = $this->container->get(UserService::class);

    // Compare the result
    $this->assertEquals($users, $service->findAllUsers());
}
于 2020-06-08T16:29:23.490 回答