'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 1:[1]
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.
Solution 2:[2]
Finngu's suggestion absolutely works. However - a big reason to split tests is to make them run in individual DB transactions. By sharing the database setup you're somewhat defeating the point.
To make independent tests that share a DB setup, you can just use subTest
.
from django.test import TestCase
class TestSubTests(ParentClass):
@classmethod
def setUpTestData(cls):
super(TestChild1, cls).setUpTestData()
cls.parent_attr = "parent value"
def test_subtests(self):
with self.subTest("The first value"):
child_attr = "child value 1"
self.assertEqual(self.parent_attr, "parent value")
self.assertEqual(self.child_attr, "child value 1")
with self.subTest("The second value"):
child_attr = "child value 2"
self.assertEqual(self.parent_attr, "parent value")
self.assertEqual(self.child_attr, "child value 2")
These subtests run independently - that means the test continues running if one subtest fails. This vs. the custom test runner is a decision that will boil down to details, but subtests are effective and sufficient in most cases. Read more on them i.e.: here.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | finngu |
Solution 2 | Jura Brazdil |