diff --git a/pytest_django/fixtures.py b/pytest_django/fixtures.py index 8c955858..24814a9a 100644 --- a/pytest_django/fixtures.py +++ b/pytest_django/fixtures.py @@ -182,6 +182,21 @@ class PytestDjangoTestCase(test_case_class): # type: ignore[misc,valid-type] if _databases is not None: databases = _databases + if VERSION >= (3, 2): + from django.test.testcases import TestData + # If the test class has defined a Django-style setUpTestData, + # arrange for it to be called by the DjangoTestCase classmethods that we're calling here. + if request.cls and hasattr(request.cls, 'setUpTestData'): + def wrappedSetUpTestData(klass): + pre_attrs = request.cls.__dict__.copy() + request.cls.setUpTestData() + for name, value in request.cls.__dict__.items(): + if value is not pre_attrs.get(name): + setattr(request.cls, name, TestData(name, value)) + + # Re-bind our new classmethod to the class we're attaching it to using the function's descriptor. + PytestDjangoTestCase.setUpTestData = wrappedSetUpTestData.__get__(PytestDjangoTestCase, PytestDjangoTestCase) + PytestDjangoTestCase.setUpClass() if VERSION >= (4, 0): request.addfinalizer(PytestDjangoTestCase.doClassCleanups) diff --git a/tests/test_database.py b/tests/test_database.py index 9016240b..52b05ebb 100644 --- a/tests/test_database.py +++ b/tests/test_database.py @@ -343,3 +343,21 @@ def test_db_access_in_test_module(self, django_testdir) -> None: 'or the "db" or "transactional_db" fixtures to enable it.' ] ) + + +# TODO: If this is omitted, the error is confusing: +# AttributeError: 'TestDatabaseClassAutoCaching' object has no attribute 'item_1' +@pytest.mark.django_db +class TestDatabaseClassAutoCaching: + + @classmethod + def setUpTestData(cls): + cls.item_1 = Item.objects.create() + + # But it's not idiomatic for pytest: + def test_foo_c(self): + self.item_1.name = 'foo' + self.item_1.save() + + def test_bar_c(self): + assert not self.item_1.name