Opened 3 months ago
Closed 2 months ago
#35660 closed Bug (fixed)
serialized_rollback fixture is not available in TransactionTestCase.setUpClass
Reported by: | Jacob Walls | Owned by: | Jacob Walls |
---|---|---|---|
Component: | Testing framework | Version: | 4.2 |
Severity: | Normal | Keywords: | rollback emulation setUpClass TransactionTestCase |
Cc: | Triage Stage: | Ready for checkin | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
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)
Change History (9)
comment:1 by , 3 months ago
Triage Stage: | Unreviewed → Accepted |
---|
comment:3 by , 2 months ago
Patch needs improvement: | set |
---|
comment:4 by , 2 months ago
Patch needs improvement: | unset |
---|
comment:5 by , 2 months ago
Patch needs improvement: | set |
---|
comment:6 by , 2 months ago
Patch needs improvement: | unset |
---|
comment:7 by , 2 months ago
Triage Stage: | Accepted → Ready for checkin |
---|
Replicated on main thank you for the detailed report
We could class this as a new feature to add support for this but I do agree that it isn't intuitive and so will leave it as a bug