Reputation: 49533
We are using PHPUnit to test parts of our application. In some tests, we want to change the value of a parameter or override a service (but only for that test, not for all tests).
What is the recommended way to configure Symfony's container on the fly in tests?
The problem we have met is that the container doesn't recompile itself when config is set on the fly (because it only recompiles itself when files have changed).
Upvotes: 7
Views: 9120
Reputation: 3358
As of Symfony 5, there is a possible shortcut. As long as all you need is to set parameters, you can simply change them in the $_ENV
variable. I.e. the following works
services.yaml
services:
App\Controller\ApiController:
arguments:
$param: '%env(my_param)%'
ApiController.php
class ApiController extends AbstractController
{
public function __construct(string $param)
{
$this->param = $param;
}
...
}
test
class ApiControllerTest extends WebTestCase
{
public function testSomething(): void
{
$_ENV['param'] = 'my-value';
$client = self::createClient();
$client->request(...)
}
...
}
Upvotes: 2
Reputation: 49533
This is how we proceed for now:
class TestKernel extends \AppKernel
{
public function __construct(\Closure $containerConfigurator, $environment = 'test', $debug = false)
{
$this->containerConfigurator = $containerConfigurator;
parent::__construct($environment, $debug);
}
public function registerContainerConfiguration(LoaderInterface $loader)
{
parent::registerContainerConfiguration($loader);
$loader->load($this->containerConfigurator);
}
/**
* Override the parent method to force recompiling the container.
* For performance reasons the container is also not dumped to disk.
*/
protected function initializeContainer()
{
$this->container = $this->buildContainer();
$this->container->compile();
$this->container->set('kernel', $this);
}
}
Then we have added this method in our PHPUnit base test class:
/**
* Rebuilds the container with custom container configuration.
*
* @param \Closure $containerConfigurator Closure that takes the ContainerBuilder and configures it.
*
* Example:
*
* $this->rebuildContainer(function (ContainerBuilder $container) {
* $container->setParameter('foo', 'bar');
* });
*/
public function rebuildContainer(\Closure $containerConfigurator) : ContainerInterface
{
if ($this->kernel) {
$this->kernel->shutdown();
$this->kernel = null;
$this->container = null;
}
$this->kernel = new TestKernel($containerConfigurator);
$this->kernel->boot();
$this->container = $this->kernel->getContainer();
return $this->container;
}
Upvotes: 5
Reputation: 1943
You do not test the container or config in Unit Tests. In Unit Tests the goal is to test the units encapsulated without the full application stack.
For functional tests the recommended way is to edit it in the inherited config under app/config/config_test.yml
All values from config_dev.yml
can be overridden there.
Upvotes: -4