#36308: Parallel testing fails reporting unit test combining subTest and
assertNumQueries
-------------------------------------+-------------------------------------
     Reporter:  Jean Bvt             |                     Type:  Bug
       Status:  new                  |                Component:  Testing
                                     |  framework
      Version:  5.2                  |                 Severity:  Normal
     Keywords:  test assertNumQuery  |             Triage Stage:
  reporting                          |  Unreviewed
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
 Updating from django 5.1.8 to 5.2.0, our test suit fails to correctly
 reports failed test.

 ```
 python manage.py test app.module.tests --parallel 8
 Found 9 test(s).
 [...]
 Destroying test database for alias 'default'...
 Destroying test database for alias 'default'...
 Destroying test database for alias 'default'...
 Traceback (most recent call last):
   File "/app/manage.py", line 23, in <module>
     main()
   File "/app/manage.py", line 19, in main
     execute_from_command_line(sys.argv)
   File "/app/.venv/lib/python3.12/site-
 packages/django/core/management/__init__.py", line 442, in
 execute_from_command_line
     utility.execute()
   File "/app/.venv/lib/python3.12/site-
 packages/django/core/management/__init__.py", line 436, in execute
     self.fetch_command(subcommand).run_from_argv(self.argv)
   File "/app/.venv/lib/python3.12/site-
 packages/django/core/management/commands/test.py", line 24, in
 run_from_argv
     super().run_from_argv(argv)
   File "/app/.venv/lib/python3.12/site-
 packages/django/core/management/base.py", line 416, in run_from_argv
     self.execute(*args, **cmd_options)
   File "/app/.venv/lib/python3.12/site-
 packages/django/core/management/base.py", line 460, in execute
     output = self.handle(*args, **options)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/app/.venv/lib/python3.12/site-
 packages/django/core/management/commands/test.py", line 63, in handle
     failures = test_runner.run_tests(test_labels)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/app/.venv/lib/python3.12/site-packages/django/test/runner.py",
 line 1099, in run_tests
     result = self.run_suite(suite)
              ^^^^^^^^^^^^^^^^^^^^^
   File "/app/.venv/lib/python3.12/site-packages/django/test/runner.py",
 line 1026, in run_suite
     return runner.run(suite)
            ^^^^^^^^^^^^^^^^^
   File "/usr/local/lib/python3.12/unittest/runner.py", line 240, in run
     test(result)
   File "/usr/local/lib/python3.12/unittest/suite.py", line 84, in __call__
     return self.run(*args, **kwds)
            ^^^^^^^^^^^^^^^^^^^^^^^
   File "/app/.venv/lib/python3.12/site-packages/django/test/runner.py",
 line 553, in run
     subsuite_index, events = test_results.next(timeout=0.1)
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/usr/local/lib/python3.12/multiprocessing/pool.py", line 873, in
 next
     raise value
 multiprocessing.pool.MaybeEncodingError: Error sending result: '(17,
 [('startTest', 0), ('addDuration', 0, 0.02817973299897858), ('addSuccess',
 0), ('stopTest', 0), ('startTest', 1), ('addDuration', 1,
 0.02015996399859432), ('addSuccess', 1), ('stopTest', 1), ('startTest',
 2), ('addDuration', 2, 0.024580582001362927), ('addSuccess', 2),
 ('stopTest', 2), ('startTest', 3), ('addSubTest', 3,
 <unittest.case._SubTest testMethod=runTest>, (<class 'AssertionError'>,
 AssertionError('3 != 2 : 3 queries executed, 2 expected\nCaptured queries
 were:\n1. SELECT "app_tokenapi"."id", "app_tokenapi"."user_id",
 "app_tokenapi"."key", "app_tokenapi"."name", "app_tokenapi"."scope_level",
 "app_tokenapi"."created_at", "app_tokenapi"."expired_at",
 "app_tokenapi"."expire_reason", "auth_user"."id", "auth_user"."password",
 "auth_user"."last_login", "auth_user"."is_superuser",
 "auth_user"."username", "auth_user"."first_name", "auth_user"."last_name",
 "auth_user"."email", "auth_user"."is_staff", "auth_user"."is_active",
 "auth_user"."date_joined" FROM "app_tokenapi" INNER JOIN "auth_user" ON
 ("app_tokenapi"."user_id" = "auth_user"."id") WHERE "app_tokenapi"."key" =
 \'abcdabcd-abcd-abcd-abcd-abcdabcd\' ORDER BY "app_tokenapi"."id" ASC
 LIMIT 1\n2. SELECT "my_models_entite"."id", "my_models_entite"."deleted",
 "my_models_entite"."deleted_by_cascade", "my_models_entite"."some_id",
 "my_models_entite"."parent_id", "my_models_entite"."type_id",
 "my_models_entite"."code", "my_models_entite"."libelle",
 "my_models_entite"."libelle_court", "my_models_entite"."url_logo",
 "my_models_entite"."begin_date", "my_models_entite"."end_date",
 "my_models_entite"."created_at", "my_models_entite"."modified_at",
 "my_models_entite"."json", "my_models_entite"."allow_externe_id",
 "my_models_entitetype"."id", "my_models_entitetype"."name",
 "my_models_entitetype"."id_rfu_link",
 "my_models_entitetype"."id_imotep_link",
 "my_models_entitetype"."created_at", "my_models_entitetype"."modified_at"
 FROM "my_models_entite" INNER JOIN "my_models_entitetype" ON
 ("my_models_entite"."type_id" = "my_models_entitetype"."id") WHERE
 "my_models_entite"."deleted" IS NULL ORDER BY "my_models_entite"."libelle"
 ASC\n3. SELECT "my_models_entite"."id", "my_models_entite"."deleted",
 "my_models_entite"."deleted_by_cascade", "my_models_entite"."some_id",
 "my_models_entite"."parent_id", "my_models_entite"."type_id",
 "my_models_entite"."code", "my_models_entite"."libelle",
 "my_models_entite"."libelle_court", "my_models_entite"."url_logo",
 "my_models_entite"."begin_date", "my_models_entite"."end_date",
 "my_models_entite"."created_at", "my_models_entite"."modified_at",
 "my_models_entite"."json", "my_models_entite"."allow_externe_id" FROM
 "my_models_entite" WHERE ("my_models_entite"."id") IN ((54), (NULL), (59),
 (62), (56), (55), (58), (57))'), <traceback object at 0x744f93f72e80>)),
 ('addDuration', 3, 0.032738704001531005), ('stopTest', 3), ('startTest',
 4), ('addDuration', 4, 0.01990954599750694), ('addSuccess', 4),
 ('stopTest', 4), ('startTest', 5), ('addDuration', 5,
 0.10901878799995757), ('addSuccess', 5), ('stopTest', 5), ('startTest',
 6), ('addDuration', 6, 0.01989884100112249), ('addSuccess', 6),
 ('stopTest', 6)])'. Reason: 'AttributeError("Can't get local object
 'convert_exception_to_response.<locals>.inner'")'
 6998993075), ('addSuccess', 6), ('stopTest', 6)])'. Reason:
 'AttributeError("Can't get local object
 'convert_exception_to_response.<locals>.inner'")'
 ```
 (I've renamed some name in this SQL queries for privacy reason)
 # the culprit test
 ```
     def test_queryset_performances(self):
         EntiteFactory.create()
         with self.subTest("sub test"):
             with self.assertNumQueries(2):
                 response = self.client.get(self.url)
 ```

 # Reproductibility
 This errors does not happen if
 - We call only this test or only its TestCase (9 tests)
 - `self.client.get(self.url)` is not called, `assertNumQueries` still
 raise AssertionError but reporting works fine.
 - replacing `self.client.get(...)` with a simpler QuerySet call still
 raise AssertionError but reporting works fine.
 - we remove `self.subTest(...)`

 The problem does not appear in django 5.1.8 because the test succeeded in
 5.1.8, it seems that 5.2 unexpectedly raised the number of query from 2 to
 3 (notice the third query look redundant with the second query) so the
 core issue with reporting may be older than 5.2.
-- 
Ticket URL: <https://code.djangoproject.com/ticket/36308>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/django-updates/0107019615b796d6-6d68575b-f80b-48e6-917b-66a042577817-000000%40eu-central-1.amazonses.com.

Reply via email to