我正在将我们的项目迁移到Symfony 4。在我的测试套件中,我们使用PHPUnit进行功能测试(我的意思是,我们调用端点并检查结果)。通常,我们模拟服务来检查不同的步骤。
自从我迁移到Symfony 4后,我就遇到了这个问题:Symfony\Component\DependencyInjection\Exception\InvalidArgumentException: The "my.service" service is already initialized, you cannot replace it.
当我们这样重新定义它时:static::$container->set("my.service", $mock);
仅用于测试,如何解决此问题?
谢谢你
6条答案
按热度按时间gmxoilav1#
自Symfony 3.3起,不建议使用替换。您应该尝试使用别名代替替换服务。http://symfony.com/doc/current/service_container/alias_private.html
你也可以试试这个方法:
执行
$container->set()
之前的$this->container->getDefinition('user.user_service')->setSynthetic(true);
在php 7.2的测试中替换Symfony服务
yiytaume2#
最后,我找到了一个解决方案。也许不是最好的,但是,它起作用了:
我创建了另一个测试容器类,并使用Reflection覆盖了
services
属性:Kernel.php:
很难看,但很有效。
sshcrbum3#
我有几个这样的测试(真实的的代码执行一些操作并返回结果,测试版本只是对每个答案返回false)。
如果您为每个环境创建并使用自定义配置(例如:一个services_test.yaml,或者在Symfony 4中可能是tests/services.yaml),并首先让它包含dev/services.yaml,但随后覆盖所需的服务,将使用最后一个定义。
app/config/services_test.yml:
在这里,我使用一个接口作为一个服务名称,但它也会做同样的'@service.name'样式。
evrscar24#
正如我所理解的,这意味着类
X
已经被注入(由于其他一些依赖关系)在您的代码试图用self::$container->set(X:class, $someMock)
覆盖它之前。4urapxun5#
对这个问题的所有答案似乎都忽略了Symfony更换服务的完整历史:
1.在Symfony 3.2之前,即使在初始化后也可以替换服务。
$service->set()
替换服务,即使是出于测试目的。1.在一些社区反馈中,DX在测试中被弃用,用
$service->set()
替换服务的能力是restored in 3.3.10,但有一个限制,即被替换的服务必须没有被“初始化”。换句话说,服务必须尚未注入到其他服务中(因为容器很难知道如何重新初始化所有服务的整个图,如果这样的服务被替换的话)。因此,如果您收到
The "my.service" service is already initialized, you cannot replace it.
消息,这意味着以下两件事之一:1.您试图替换的服务已用于初始化另一个服务。您可能需要在测试的早期替换该服务,或者重新排列测试中初始化服务的顺序。
lazy
服务。惰性服务在定义后立即由容器注入一个惰性加载存根,这会导致容器将其视为已初始化。作为一种解决方法,在services_test.yaml
文件中将lazy
服务定义为非惰性。我通过单步执行具有惰性服务的项目中的代码发现了这一点,这是我不得不使用的变通方法。xmjla07d6#
如果您使用Symfony 3.4及以下版本,您可以在容器中进行服务,无论它是私有的还是公共的。只会发出deprication通知,内容类似于问题的错误消息。
在Symfony 4.0上,发现了问题的错误。
但是在Symfony 4.1及更高版本上,你可以依靠特殊的“测试”容器。要学习如何使用它,请考虑以下链接: