Symfony 5:如何在集成测试中模拟 HttpClientInterface?

Lun*_*man 3 php dependency-injection functional-testing symfony

我有一个控制器端点,它在后台执行外部 API 请求,但我每次运行测试时都无法真正发出该请求。

我用来HttpClientInterface提出请求,现在我的想法是将其替换为MockHttpClient. 到目前为止,这是我所拥有的:

class MyControllerTest extends WebTestCase
{
    public function testSomething(): void
    {
        $client = static::createClient();

        $response = new MockResponse(null, ['http_code' => 200]);
        $client->getContainer()->set(HttpClientInterface::class, new MockHttpClient($response));

        $client->request('GET', '/my-end-point');

        self::assertResponseIsSuccessful();
    }
}
Run Code Online (Sandbox Code Playgroud)

但它给了我以下错误:

The "Symfony\Contracts\HttpClient\HttpClientInterface" service is private, you cannot replace it
Run Code Online (Sandbox Code Playgroud)

这有点道理。有没有更好的解决方案或者如何克服这个问题?

小智 5

在 Symfony 环境中,服务是私有的,但这不是问题,因为您通过依赖注入将它们放入控制器、服务等中,这意味着 Symfony 本身会处理它。

当尝试测试时,您可能最终会像您的情况一样,直接在容器中设置模拟类。

这将引发您看到的错误。

要解决此错误,请在 config 文件夹中的 services.yaml 文件中,只需在底部添加以下行:

when@test:
    services:
        _defaults:
            public: true

        test.Symfony\Contracts\HttpClient\HttpClientInterface: '@Symfony\Contracts\HttpClient\HttpClientInterface'
Run Code Online (Sandbox Code Playgroud)

你在这里所做的,是告诉 Symfony 在测试期间你将有一个名为 test.Symfony\Contracts\HttpClient\HttpClientInterface 的公共服务,它是 HTTPClientInterface 类的副本。

现在,在您的测试代码中您可以执行以下操作:

$response = new MockResponse(null, ['http_code' => 200]);
$client->getContainer()->set('test.Symfony\Contracts\HttpClient\HttpClientInterface', new TraceableHttpClient(new MockHttpClient($response)));
Run Code Online (Sandbox Code Playgroud)

  • 不。真正解决的是 `$client->getContainer()->set('test.Symfony\Contracts\HttpClient\HttpClientInterface', new TraceableHttpClient(new MockHttpClient($response)))` (2认同)