Disable doctrine cache for test environment / unittests (symfony 4)

3.5k Views Asked by At

I have a unittests in my Symfony 4 project which show a inconsistent behaviour and I suspect the doctrine caching is responsible for this. So I am looking for a way to disable caching for Unittests.

My current packages/test/doctrine.yaml file for the environment test looks like this:

doctrine:
    orm:
        auto_generate_proxy_classes: false
        metadata_cache_driver:
            type: service
            id: doctrine.system_cache_provider
        query_cache_driver:
            type: service
            id: doctrine.system_cache_provider
        result_cache_driver:
            type: service
            id: doctrine.result_cache_provider

services:
    doctrine.result_cache_provider:
        class: Symfony\Component\Cache\DoctrineProvider
        public: false
        arguments:
            - '@doctrine.result_cache_pool'
    doctrine.system_cache_provider:
        class: Symfony\Component\Cache\DoctrineProvider
        public: false
        arguments:
            - '@doctrine.system_cache_pool'

framework:
    cache:
        pools:
            doctrine.result_cache_pool:
                adapter: cache.app
            doctrine.system_cache_pool:
                adapter: cache.system

If I want to disable any caching in doctrine for tests, is there any cache driver, which is a non-caching dummy? If I leave those entries empty I guess my prod settings or the general settings would be used, which means the results would also be cached. Can I explicitly non-cache? I hope I would not have to write an explicit dummy cache provider, who doesn't cache? This could be a solution, but it looks to me like this should be achieved more easily.

config
    \__packages
        |
        |__ prod
        |   \__doctrine.yaml
        |
        |__ dev
        |   \__doctrine.yaml
        |
        |__ test
        |   \__doctrine.yaml
        |
        \__doctrine.yaml

This is my extended KernelTestCase class:

protected EntityManagerInterface $em;

public static function setUpBeforeClass(): void
{
    parent::setUpBeforeClass();

    $kernel = static::createKernel();
    $kernel->boot();
    $em = $kernel
        ->getContainer()
        ->get('doctrine')
        ->getManager();
    $schemaTool = new SchemaTool($em);
    $metadata = $em
        ->getMetadataFactory()
        ->getAllMetadata();

    // Drop and recreate tables for all entities
    $schemaTool->dropSchema($metadata);
    $schemaTool->createSchema($metadata);
}


protected function setUp(): void
{
    parent::setUp();
    self::ensureKernelShutdown();

    $kernel = static::createKernel();
    $kernel->boot();

    $this->em = $kernel
        ->getContainer()
        ->get('doctrine')
        ->getManager();

    // loads tests data for every tests
    $projectDir = $kernel->getProjectDir();
    system('php ' . $projectDir . '/bin/console doctrine:fixtures:load --env=test -n -q');
}

....

protected function tearDown(): void
{
    parent::tearDown();
    if (null !== $this->em) {
        $this->em->close();
    }
}
2

There are 2 best solutions below

6
On

cache configuration

If I leave those entries empty I guess my prod settings or the general settings would be used

No, the settings from prod will never ever be used in test environment. Test uses the configuration from config/packages/test/ and does fallback to the general settings in config/packages/ but never to prod.

In a typical setup, general doctrine stuff like mappings are defined in config/packages/doctrine.yaml, cache is only defined in config/packages/prod/doctrine.yaml. See official symfony demo application

You can also verify your configuration using bin/console debug:config doctrine --env=test.

test isolation

Your problem is most probably not caused by doctrine cache configuration but by poor isolation of your testcases.

Have a look at Functional Testing of A Doctrine Repository. Symfonys official docs recommend to boot the kernel at setUp() and to close the entity manager during tearDown().

If that complete isolation is not a feasible approach for you, you will have to debug to find out which testcase causes the breach of isolation. If you pinned the causing testcase you should check its execution path and look out for missing doctrine flushes and for transactions that are left open longer than expected.

0
On

Thanks to the advice of everybody here it looks like I have finally fixed my problem. At least all tests are green in now 40 runs.

What I did:

Before I was manually loading my fixtures for each test and experimented with recreating the db for each testclass and then for each test. I threw that away completely and now rely solely on the Dama Bundle and the transaction rollback to get unmodified test data.

dama_doctrine_test:
    enable_static_connection: true
    enable_static_meta_data_cache: false
    enable_static_query_cache: false
    

In the configuration of the Dama Bundle I did set the caches for the queries and meta data to false. I am not sure if this is necessary though. But since it didn't slow down my tests I keep it.

This combination finally did do the trick.

Thanks to @domis86 @simon.ro for your support and patience!

https://symfony.com/doc/4.4/testing/database.html#resetting-the-database-automatically-before-each-test https://github.com/dmaicher/doctrine-test-bundle