#35660: serialized_rollback fixture is not available in
TransactionTestCase.setUpClass
-------------------------------------+-------------------------------------
Reporter: Jacob | Owner: Jacob Walls
Walls |
Type: Bug | Status: assigned
Component: Testing | Version: 4.2
framework | Keywords: rollback emulation
Severity: Normal | setUpClass TransactionTestCase
Triage Stage: | Has patch: 0
Unreviewed |
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------+-------------------------------------
`serialized_rollback=True` allows subsequent `TransactionTestCase` classes
to continue depending on the data created in the app's initial migration
after a previous `TransactionTestCase` truncated tables.
By trial and error, I found that I couldn't depend on this emulated
rollback during the `setUpClass()` phase, but rather during the `setUp()`
phase only. This results in a difficult DX when debugging `setUpClass()`
failures in tests that pass in isolation, and resorting to `setUp()` (as I
ultimately did) has a performance penalty.
`TestCase` loads fixtures before running `setUpClass()`. Can we explore
letting `TransactionTestCase` do the same? I imagine the refactor involves
implementing `TransactionTestCase.setUpClass()`.
Nothing in the docs advises that the emulated rollback is only available
during certain parts of the test lifecycle, so at the very least I'd
suggest a docs update. Happy to cross-post to forum if this isn't a "bug".
----
**Sample project**
models.py
{{{
from django.db import models
class MyModel(models.Model):
flag = models.BooleanField()
}}}
migrations/0001_initial.py
{{{
# Generated by Django 4.2.15 on 2024-08-06 19:34
from django.db import migrations, models
def seed_data(apps, schema_editor):
MyModel = apps.get_model("fooapp", "MyModel")
MyModel.objects.create(flag=True)
class Migration(migrations.Migration):
initial = True
dependencies = []
operations = [
migrations.CreateModel(
name="MyModel",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("flag", models.BooleanField()),
],
),
migrations.RunPython(seed_data, migrations.RunPython.noop),
]
}}}
tests.py
{{{
from django.test import TransactionTestCase
from .models import MyModel
def depend_on_fixture():
assert MyModel.objects.count()
class A(TransactionTestCase):
serialized_rollback = True
@classmethod
def setUpClass(cls):
depend_on_fixture()
def test_a(self):
pass
class B(TransactionTestCase):
serialized_rollback = True
@classmethod
def setUpClass(cls):
depend_on_fixture()
def test_b(self):
pass
}}}
Gives only one failure, which you'll miss if developing the tests in
isolation:
{{{
======================================================================
ERROR: setUpClass (fooapp.tests.B)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/jwalls/foo/fooapp/tests.py", line 25, in setUpClass
depend_on_fixture()
File "/Users/jwalls/foo/fooapp/tests.py", line 6, in depend_on_fixture
assert MyModel.objects.count()
AssertionError
----------------------------------------------------------------------
Ran 1 test in 0.004s
FAILED (errors=1)
}}}
--
Ticket URL: <
https://code.djangoproject.com/ticket/35660>
Django <
https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.