When I run tests in parallel, I get random failures because one test interferes with the cache of another test.
I can work around the problem with
@override_settings(
CACHES={
"default": {
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
"LOCATION": "[random_string]",
}
},
)
Actually to make that smaller I created a @isolate_cache decorator that is a wrapper around override_settings.
But still I need to go and decorate a large number of test cases. This is error prone, because, as I said, the failures are random. I might run the test suite 100 times without error and think that everything is OK, but I still might have forgotten to decorate a test case, and at some point it will fail randomly.
I've also thought about creating my own TestCase subclass and use only that for all my test cases. This presents a similar problem: at some point someone would inherit from django.test.TestCase out of habit, and it might not fail for a long time. Besides, some of my tests inherit from rest_framework.test.APITestCase (or other classes), so there isn't a single test case subclass.
Is there any way to tell Django to run each test case in an isolated section of the cache once and for all?
You don't need "an isolated section of the cache", just to clear cache between tests.
Here are a few ways.
TestCaseThe 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()
TestCase.tearDownAssuming 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
TestSuiteYou 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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With