首页 > 解决方案 > Symfony 5:如何在集成测试中模拟 HttpClientInterface?

问题描述

我有一个控制器端点,它在引擎盖下执行一个外部 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();
    }
}

但它给了我以下错误:

The "Symfony\Contracts\HttpClient\HttpClientInterface" service is private, you cannot replace it

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

标签: phpsymfonydependency-injectionfunctional-testing

解决方案


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

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

这将抛出您看到的错误。

为了克服这个错误,在位于 config 文件夹中的 services.yaml 文件中,只需在底部添加以下行:

when@test:
    services:
        _defaults:
            public: true

        test.Symfony\Contracts\HttpClient\HttpClientInterface: '@Symfony\Contracts\HttpClient\HttpClientInterface'

您在这里所做的是告诉 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)));

推荐阅读