@@ -201,6 +201,47 @@ def django_db_setup(
201
201
)
202
202
203
203
204
+ def _build_pytest_django_test_case (
205
+ test_case_class ,
206
+ * ,
207
+ reset_sequences : bool ,
208
+ serialized_rollback : bool ,
209
+ databases ,
210
+ available_apps ,
211
+ skip_django_testcase_class_setup : bool ,
212
+ ):
213
+ # Build a custom TestCase subclass with configured attributes and optional
214
+ # overrides to skip Django's TestCase class-level setup/teardown.
215
+ import django .test # local import to avoid hard dependency at import time
216
+
217
+ _reset_sequences = reset_sequences
218
+ _serialized_rollback = serialized_rollback
219
+ _databases = databases
220
+ _available_apps = available_apps
221
+
222
+ class PytestDjangoTestCase (test_case_class ): # type: ignore[misc,valid-type]
223
+ reset_sequences = _reset_sequences
224
+ serialized_rollback = _serialized_rollback
225
+ if _databases is not None :
226
+ databases = _databases
227
+ if _available_apps is not None :
228
+ available_apps = _available_apps
229
+
230
+ if skip_django_testcase_class_setup :
231
+
232
+ @classmethod
233
+ def setUpClass (cls ) -> None : # type: ignore[override]
234
+ # Skip django.test.TestCase.setUpClass, call its super instead
235
+ super (django .test .TestCase , cls ).setUpClass ()
236
+
237
+ @classmethod
238
+ def tearDownClass (cls ) -> None : # type: ignore[override]
239
+ # Skip django.test.TestCase.tearDownClass, call its super instead
240
+ super (django .test .TestCase , cls ).tearDownClass ()
241
+
242
+ return PytestDjangoTestCase
243
+
244
+
204
245
@pytest .fixture
205
246
def _sync_django_db_helper (
206
247
request : pytest .FixtureRequest ,
@@ -248,41 +289,14 @@ def _sync_django_db_helper(
248
289
else :
249
290
test_case_class = django .test .TestCase
250
291
251
- _reset_sequences = reset_sequences
252
- _serialized_rollback = serialized_rollback
253
- _databases = databases
254
- _available_apps = available_apps
255
-
256
- class PytestDjangoTestCase (test_case_class ): # type: ignore[misc,valid-type]
257
- reset_sequences = _reset_sequences
258
- serialized_rollback = _serialized_rollback
259
- if _databases is not None :
260
- databases = _databases
261
- if _available_apps is not None :
262
- available_apps = _available_apps
263
-
264
- # For non-transactional tests, skip executing `django.test.TestCase`'s
265
- # `setUpClass`/`tearDownClass`, only execute the super class ones.
266
- #
267
- # `TestCase`'s class setup manages the `setUpTestData`/class-level
268
- # transaction functionality. We don't use it; instead we (will) offer
269
- # our own alternatives. So it only adds overhead, and does some things
270
- # which conflict with our (planned) functionality, particularly, it
271
- # closes all database connections in `tearDownClass` which inhibits
272
- # wrapping tests in higher-scoped transactions.
273
- #
274
- # It's possible a new version of Django will add some unrelated
275
- # functionality to these methods, in which case skipping them completely
276
- # would not be desirable. Let's cross that bridge when we get there...
277
- if not transactional :
278
-
279
- @classmethod
280
- def setUpClass (cls ) -> None :
281
- super (django .test .TestCase , cls ).setUpClass ()
282
-
283
- @classmethod
284
- def tearDownClass (cls ) -> None :
285
- super (django .test .TestCase , cls ).tearDownClass ()
292
+ PytestDjangoTestCase = _build_pytest_django_test_case (
293
+ test_case_class ,
294
+ reset_sequences = reset_sequences ,
295
+ serialized_rollback = serialized_rollback ,
296
+ databases = databases ,
297
+ available_apps = available_apps ,
298
+ skip_django_testcase_class_setup = (not transactional ),
299
+ )
286
300
287
301
PytestDjangoTestCase .setUpClass ()
288
302
@@ -319,9 +333,6 @@ async def _async_django_db_helper(
319
333
) -> AsyncGenerator [None , None ]:
320
334
# same as _sync_django_db_helper, except for running the transaction start and rollback wrapped in a
321
335
# `sync_to_async` call
322
- if is_django_unittest (request ):
323
- yield
324
- return
325
336
transactional , reset_sequences , databases , serialized_rollback , available_apps = (
326
337
_get_django_db_settings (request )
327
338
)
@@ -330,46 +341,16 @@ async def _async_django_db_helper(
330
341
import django .db
331
342
import django .test
332
343
333
- if transactional :
334
- test_case_class = django .test .TransactionTestCase
335
- else :
336
- test_case_class = django .test .TestCase
337
-
338
- _reset_sequences = reset_sequences
339
- _serialized_rollback = serialized_rollback
340
- _databases = databases
341
- _available_apps = available_apps
342
-
343
- class PytestDjangoTestCase (test_case_class ): # type: ignore[misc,valid-type]
344
- reset_sequences = _reset_sequences
345
- serialized_rollback = _serialized_rollback
346
- if _databases is not None :
347
- databases = _databases
348
- if _available_apps is not None :
349
- available_apps = _available_apps
350
-
351
- # For non-transactional tests, skip executing `django.test.TestCase`'s
352
- # `setUpClass`/`tearDownClass`, only execute the super class ones.
353
- #
354
- # `TestCase`'s class setup manages the `setUpTestData`/class-level
355
- # transaction functionality. We don't use it; instead we (will) offer
356
- # our own alternatives. So it only adds overhead, and does some things
357
- # which conflict with our (planned) functionality, particularly, it
358
- # closes all database connections in `tearDownClass` which inhibits
359
- # wrapping tests in higher-scoped transactions.
360
- #
361
- # It's possible a new version of Django will add some unrelated
362
- # functionality to these methods, in which case skipping them completely
363
- # would not be desirable. Let's cross that bridge when we get there...
364
- if not transactional :
365
-
366
- @classmethod
367
- def setUpClass (cls ) -> None :
368
- super (django .test .TestCase , cls ).setUpClass ()
369
-
370
- @classmethod
371
- def tearDownClass (cls ) -> None :
372
- super (django .test .TestCase , cls ).tearDownClass ()
344
+ test_case_class = django .test .TestCase
345
+
346
+ PytestDjangoTestCase = _build_pytest_django_test_case (
347
+ test_case_class ,
348
+ reset_sequences = reset_sequences ,
349
+ serialized_rollback = serialized_rollback ,
350
+ databases = databases ,
351
+ available_apps = available_apps ,
352
+ skip_django_testcase_class_setup = True ,
353
+ )
373
354
374
355
from asgiref .sync import sync_to_async
375
356
0 commit comments