[Solved]-Django cache isolation when running tests in parallel

7👍

You don’t need "an isolated section of the cache", just to clear cache between tests.

Here are a few ways.

1. Subclass TestCase

The question mentions this is not desired, but I should still mention this proper way.

from django.core.cache import cache
from django.test import TestCase


class CacheClearTestCase(TestCase):

    def tearDown(self):
        # super().tearDown()
        cache.clear()

2. Patch TestCase.tearDown

Assuming subclasses that override tearDown call super().tearDown(), you could do this.

Add this in manage.py before execute_from_command_line(sys.argv):

if sys.argv[1] == 'test':
    from django.test import TestCase
    from django.core.cache import cache
    TestCase.tearDown = cache.clear

3. Subclass TestSuite

You can clear the cache after each test by subclassing TestSuite to override _removeTestAtIndex and setting DiscoverRunner.test_suite to that subclass.

Add this in manage.py before execute_from_command_line(sys.argv):

if sys.argv[1] == 'test':
    from unittest import TestSuite
    from django.core.cache import cache
    from django.test.runner import DiscoverRunner

    class CacheClearTestSuite(TestSuite):
        def _removeTestAtIndex(self, index):
            super()._removeTestAtIndex(index)
            cache.clear()

    DiscoverRunner.test_suite = CacheClearTestSuite

Why you don’t need an isolated section of the cache

To be clear, this is not a problem caused by running tests in parallel.

From https://docs.djangoproject.com/en/4.0/ref/django-admin/#cmdoption-test-parallel:

--parallel [N]

Runs tests in separate parallel processes.

From https://docs.djangoproject.com/en/4.0/topics/cache/#local-memory-caching-1:

Note that each process will have its own private cache instance, which means no cross-process caching is possible.

👤aaron

0👍

The easiest solution would be to have a separate settings file for tests that you can load in manage.py. This can also import all of your default settings.

manage.py

    settings = 'my_project.test_settings' if 'test' in sys.argv else 'my_project.settings'
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", settings)

test_settings.py

from .settings import *  # import default settings

# setting overrides here

CACHES = {
    "default": {
        "BACKEND": "django.core.cache.backends.locmem.LocMemCache",
        "LOCATION": "[random_string]",
    }
}

If you need to do more settings overrides, especially for multiple environments, I would recommend using something like django-configurations.

👤Brobin

Leave a comment