I am migrating our project to Symfony 4. In my test suites, we used PHPUnit for functional tests (I mean, we call endpoints and we check result). Often, we mock services to check different steps.
Since I migrated to Symfony 4, I am facing this issue: Symfony\Component\DependencyInjection\Exception\InvalidArgumentException: The "my.service" service is already initialized, you cannot replace it.
when we redefine it like this : static::$container->set("my.service", $mock);
Only for tests, how can I fix this issue?
Finally, I found a solution. Maybe not the best, but, it's working:
I created another test container class and I override the services
property using Reflection:
<?php
namespace My\Bundle\Test;
use Symfony\Bundle\FrameworkBundle\Test\TestContainer as BaseTestContainer;
class TestContainer extends BaseTestContainer
{
private $publicContainer;
public function set($id, $service)
{
$r = new \ReflectionObject($this->publicContainer);
$p = $r->getProperty('services');
$p->setAccessible(true);
$services = $p->getValue($this->publicContainer);
$services[$id] = $service;
$p->setValue($this->publicContainer, $services);
}
public function setPublicContainer($container)
{
$this->publicContainer = $container;
}
Kernel.php :
<?php
namespace App;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
class Kernel extends BaseKernel
{
use MicroKernelTrait;
public function getOriginalContainer()
{
if(!$this->container) {
parent::boot();
}
/** @var Container $container */
return $this->container;
}
public function getContainer()
{
if ($this->environment == 'prod') {
return parent::getContainer();
}
/** @var Container $container */
$container = $this->getOriginalContainer();
$testContainer = $container->get('my.test.service_container');
$testContainer->setPublicContainer($container);
return $testContainer;
}
It's really ugly, but it's working.