Description
This module sets a instance of the entity manager in the container because this is hard coded as a persistent service.
This results in all doctrine event listeners being instantiated on the first call, and those references end up in the entity manager.
However, when the kernel reboots, and a new test is started only the entity manager itself is set on the container. All listeners and their dependencies are still marked as uninitialized in the new container.
When a Doctrine event listener and another random service have the same service as a dependency, the latter will end up with a new instance of that dependency every test. while the doctrine listener will always be stuck with the original instance of the dependency.
This effectively breaks the shared services
since there are now multiple instances, And the original service only known to doctrine can never be accessed anymore by the new kernel or the test code.
This is a simple use case to show the issue:
- doctrine listener keeps track of flushes
- test validates amount of flushed happened
class TestSubscriber implements EventSubscriberInterface
{
public $flushes = 0;
public function getSubscribedEvents(): array { return [Events::onFlush]; }
public function __invoke() { $this->flushed++; }
}
class MyTest extends FunctionalTestCase
{
public function it_can_inspect_doctrine_event_listeners(): void
{
$subscriber = $this->tester->grabService(TestSubscriber::class);
$this->tester->assertSame(1, $subscriber->flushes);
}
}
This test will always fail, because the instance of TestSubscriber
in the test case's container is never the same as the one in the container's entity manager instance.
Again, this is a very simple test case, but when subscribers also have dependencies from the container they all get decoupled from the actual test case's container, and can never be accessed anymore.