#35402: DatabaseFeatures.django_test_skips crashes when it references a class in
another test module
-------------------------------------+-------------------------------------
               Reporter:  Tim        |          Owner:  nobody
  Graham                             |
                   Type:  Bug        |         Status:  new
              Component:  Database   |        Version:  dev
  layer (models, ORM)                |
               Severity:  Normal     |       Keywords:
           Triage Stage:             |      Has patch:  0
  Unreviewed                         |
    Needs documentation:  0          |    Needs tests:  0
Patch needs improvement:  0          |  Easy pickings:  0
                  UI/UX:  0          |
-------------------------------------+-------------------------------------
 Since the introduction of `DatabaseFeatures.django_test_skips` (#32178),
 I've used it to skip test classes, however, this can crash if there are
 multiple test modules in a package.

 To reproduce, first make this modification to skip a class
 {{{#!diff
 diff --git a/django/db/backends/sqlite3/features.py
 b/django/db/backends/sqlite3/features.py
 index d95c6fb2d1..51229fe970 100644
 --- a/django/db/backends/sqlite3/features.py
 +++ b/django/db/backends/sqlite3/features.py
 @@ -68,8 +68,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
      def django_test_skips(self):
          skips = {
              "SQLite stores values rounded to 15 significant digits.": {
 -                "model_fields.test_decimalfield.DecimalFieldTests."
 -                "test_fetch_from_db_without_float_rounding",
 +                "model_fields.test_decimalfield.DecimalFieldTests",
              },
              "SQLite naively remakes the table on field alteration.": {
 }}}

 Then try to execute a test module in `model_fields` besides the one with
 the skip:
 {{{#!shell
 $ ./tests/runtests.py model_fields.test_autofield
 Testing against Django installed in '/home/tim/code/django/django' with up
 to 3 processes
 Found 62 test(s).
 Creating test database for alias 'default'...
 Traceback (most recent call last):
   File "/home/tim/code/django/django/utils/module_loading.py", line 30, in
 import_string
     return cached_import(module_path, class_name)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/home/tim/code/django/django/utils/module_loading.py", line 16, in
 cached_import
     return getattr(module, class_name)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 AttributeError: module 'model_fields' has no attribute 'test_decimalfield'

 The above exception was the direct cause of the following exception:

 Traceback (most recent call last):
   File "/home/tim/code/django/./tests/runtests.py", line 784, in <module>
     failures = django_tests(
                ^^^^^^^^^^^^^
   File "/home/tim/code/django/./tests/runtests.py", line 422, in
 django_tests
     failures = test_runner.run_tests(test_labels)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/home/tim/code/django/django/test/runner.py", line 1066, in
 run_tests
     old_config = self.setup_databases(
                  ^^^^^^^^^^^^^^^^^^^^^
   File "/home/tim/code/django/django/test/runner.py", line 964, in
 setup_databases
     return _setup_databases(
            ^^^^^^^^^^^^^^^^^
   File "/home/tim/code/django/django/test/utils.py", line 206, in
 setup_databases
     connection.creation.create_test_db(
   File "/home/tim/code/django/django/db/backends/base/creation.py", line
 102, in create_test_db
     self.mark_expected_failures_and_skips()
   File "/home/tim/code/django/django/db/backends/base/creation.py", line
 356, in mark_expected_failures_and_skips
     test_case = import_string(test_case_name)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/home/tim/code/django/django/utils/module_loading.py", line 32, in
 import_string
     raise ImportError(
 ImportError: Module "model_fields" does not define a "test_decimalfield"
 attribute/class
 }}}

 A naive fix:
 {{{#!diff
 diff --git a/django/db/backends/base/creation.py
 b/django/db/backends/base/creation.py
 index 6856fdb596..f6cc270b16 100644
 --- a/django/db/backends/base/creation.py
 +++ b/django/db/backends/base/creation.py
 @@ -350,6 +350,9 @@ class BaseDatabaseCreation:
                  test_app = test_name.split(".")[0]
                  # Importing a test app that isn't installed raises
 RuntimeError.
                  if test_app in settings.INSTALLED_APPS:
 +                    # If this is a a test class, it may need to be
 imported.
 +                    if test_name.count(".") == 2:
 +                        import_string(test_name)
                      test_case = import_string(test_case_name)
                      test_method = getattr(test_case, test_method_name)
                      setattr(test_case, test_method_name,
 skip(reason)(test_method))
 }}}
-- 
Ticket URL: <https://code.djangoproject.com/ticket/35402>
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 django-updates+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/0107018f10ae9e2b-c223f599-eff4-492e-bde1-85500a28f536-000000%40eu-central-1.amazonses.com.

Reply via email to