Search code examples
pythondjangodjango-testing

Inherinting Django SetUpTestData method called for each child


Inheriting a mother class make its classmethod setUpTestData called for each child class. This is what I excepted but not what I want.

Here is a minimalist example

from django.test import TestCase


class ParentClass(TestCase):
    @classmethod
    def setUpTestData(cls):
        cls.parent_attr = "parent value" 
        print("ParentClass.setUpTestData called") # this is called twice


class TestChild1(ParentClass):
    @classmethod
    def setUpTestData(cls):
        super(TestChild1, cls).setUpTestData()
        cls.child_attr = "child value 1"

    def test_child(self):
        self.assertEqual(self.parent_attr, "parent value")
        self.assertEqual(self.child_attr, "child value 1")


class TestChild2(ParentClass):
    @classmethod
    def setUpTestData(cls):
        super(TestChild2, cls).setUpTestData()
        cls.child_attr = "child value 2"

    def test_child(self):
        self.assertEqual(self.parent_attr, "parent value")
        self.assertEqual(self.child_attr, "child value 2")

$ python manage.py test accounts.tests.test_test
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
ParentClass.setUpTestData called
.ParentClass.setUpTestData called
.
----------------------------------------------------------------------
Ran 2 tests in 0.006s

OK
Destroying test database for alias 'default'...

I want to be able to make many child class where each child class would apply tiny modification to the common 'inherited' database. However I do not want to run many time the parent classmethod as it is very slow.

How can I ensure parent database is generated only once and that every child class works on a copy of parent database instead of regenerating the entire database.


Solution

  • As you have stated yourself and @brian-destura pointed out as well, your best option to share data between test classes would be implementing your own test runner.

    The runner should inherit from django.test.runner.DiscoverRunner. In that runner, you could override setup_test_environment() (docs) or setup_databases() (docs) depending on your needs.