英文:
Symfony tests how to pass depencencies to services via container
问题
我正在为一个Symfony 4.4应用编写测试,我需要模拟一个名为TokenService
的服务,它是我需要测试的一些类(repositories、services)的依赖项,但我不确定如何通过DI传递一些依赖项:
self::$container->get('App\Services\classToTest') // 无法传递依赖项?
我是否被迫实例化该类并执行类似以下操作:
$classToTest = new \App\Services\classToTest($depencencyOne, $tokenMock, ...)
此外,我只需要模拟其中一个依赖项,所以我是否仍然必须传递所有其他依赖项?
英文:
I'm writing tests for a Symfony 4.4 app and I need to mock a service named TokenService
which is a dependency of some classes that I need to test (repositories, services), but I'm not sure how to proceed to pass some dependencies via DI :
self::$container->get('App\Services\classToTest') // Not able to pass dependencies ?
Am I forced to instantiate the class and do something like this :
$classToTest = new \App\Services\classToTest($depencencyOne,$tokenMock,...)
Also, I need to mock only one of the dependencies, so do I have to pass all the other dependencies anyway ?
答案1
得分: 1
你可以从测试服务容器中使用get()
,但也可以使用set()
!
我可以提供一个最近遇到的真实示例,其中我需要在某些测试中替换HttpClient为其模拟实现:
// 在这里,我用模拟实现替换了服务(PHPUnit模拟也可以使用)
self::getContainer()->set(HttpClientInterface::class, new MockHttpClient([
new MockResponse('{"some":"JSON"}'),
new MockResponse('{"other":"JSON"}'),
]));
// 这里$myService将获得模拟注入,而不是原始的HTTP客户端
$myService = self::getContainer()->get(MyService::class);
但需要注意,我必须将服务设置为公共的才能允许覆盖它:
# services.yaml
when@test:
services:
Symfony\Contracts\HttpClient\HttpClientInterface:
alias: '.debug.http_client'
public: true
如果您不能或不想替换服务容器中的依赖项,那么是的,您将需要自己实例化被测试的服务并获取每个依赖项:
$myService = new MyService(
self::getContainer()->get(RealService::class),
$someMockDependency
);
如果问题源自您自己的代码,请确保遵循良好的实践,以使您的代码更容易进行测试(主要是依赖注入和依赖反转原则)。
英文:
You can get()
from the testing service container but you can also set()
!
I can give a real example I recently had where I needed to replace the HttpClient with its mock implementation in some tests:
// Here I replace the service with a mock implementation (a PHPUnit mock can work too)
self::getContainer()->set(HttpClientInterface::class, new MockHttpClient([
new MockResponse('{"some":"JSON"}'),
new MockResponse('{"other":"JSON"}'),
]));
// Here $myService will get the mock injected instead of the original HTTP Client
$myService = self::getContainer()->get(MyService::class);
But it should be noted that I had to make the service public to be allowed to overwrite it:
# services.yaml
when@test:
services:
Symfony\Contracts\HttpClient\HttpClientInterface:
alias: '.debug.http_client'
public: true
If you don't (or can't) replace a dependency in the service container, then yes you will need to instantiate the tested service yourself and get every dependency:
$myService = new MyService(
self::getContainer()->get(RealService::class),
$someMockDependency
);
If the issue comes from your own code, be sure to follow good practices to make your code easier to test (mostly dependency injection and dependency inversion principles).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论