瀏覽代碼

Fixed #28869 -- Made tagged test classes and methods inherit tags from parents.

Will Ayd 7 年之前
父節點
當前提交
09530e61a0

+ 1 - 0
AUTHORS

@@ -832,6 +832,7 @@ answer newbie questions, and generally made Django that much better:
     Wiktor Kołodziej <wiktor@pykonik.org>
     Wiley Kestner <wiley.kestner@gmail.com>
     Wiliam Alves de Souza <wiliamsouza83@gmail.com>
+    Will Ayd <william.ayd@icloud.com>
     William Schwartz <wkschwartz@gmail.com>
     Will Hardy <django@willhardy.com.au>
     Wilson Miner <wminer@gmail.com>

+ 4 - 1
django/test/utils.py

@@ -831,6 +831,9 @@ class isolate_apps(TestContextDecorator):
 def tag(*tags):
     """Decorator to add tags to a test class or method."""
     def decorator(obj):
-        setattr(obj, 'tags', set(tags))
+        if hasattr(obj, 'tags'):
+            obj.tags = obj.tags.union(tags)
+        else:
+            setattr(obj, 'tags', set(tags))
         return obj
     return decorator

+ 1 - 0
docs/spelling_wordlist

@@ -695,6 +695,7 @@ subviews
 subwidget
 subwidgets
 superclass
+superclasses
 superset
 swappable
 symlink

+ 19 - 0
docs/topics/testing/tools.txt

@@ -1619,6 +1619,25 @@ You can also tag a test case::
     class SampleTestCase(TestCase):
         ...
 
+Subclasses inherit tags from superclasses, and methods inherit tags from their
+class. Given::
+
+    @tag('foo')
+    class SampleTestCaseChild(SampleTestCase):
+
+        @tag('bar')
+        def test(self):
+            ...
+
+``SampleTestCaseChild.test`` will be labeled with ``'slow'``, ``'core'``,
+``'bar'``, and ``'foo'``.
+
+.. versionchanged:: 2.1
+
+   In older versions, tagged tests don't inherit tags from classes, and
+   tagged subclasses don't inherit tags from superclasses. For example,
+   ``SampleTestCaseChild.test`` is labeled only with ``'bar'``.
+
 Then you can choose which tests to run. For example, to run only fast tests:
 
 .. code-block:: console

+ 12 - 0
tests/test_runner/test_discover_runner.py

@@ -198,3 +198,15 @@ class DiscoverRunnerTest(TestCase):
         self.assertEqual(runner.build_suite(['test_runner_apps.tagged.tests']).countTestCases(), 0)
         runner = DiscoverRunner(exclude_tags=['slow'])
         self.assertEqual(runner.build_suite(['test_runner_apps.tagged.tests']).countTestCases(), 0)
+
+    def test_tag_inheritance(self):
+        def count_tests(**kwargs):
+            suite = DiscoverRunner(**kwargs).build_suite(['test_runner_apps.tagged.tests_inheritance'])
+            return suite.countTestCases()
+
+        self.assertEqual(count_tests(tags=['foo']), 4)
+        self.assertEqual(count_tests(tags=['bar']), 2)
+        self.assertEqual(count_tests(tags=['baz']), 2)
+        self.assertEqual(count_tests(tags=['foo'], exclude_tags=['bar']), 2)
+        self.assertEqual(count_tests(tags=['foo'], exclude_tags=['bar', 'baz']), 1)
+        self.assertEqual(count_tests(exclude_tags=['foo']), 0)

+ 29 - 0
tests/test_runner_apps/tagged/tests_inheritance.py

@@ -0,0 +1,29 @@
+from unittest import TestCase
+
+from django.test import tag
+
+
+@tag('foo')
+class FooBase(TestCase):
+    pass
+
+
+class Foo(FooBase):
+
+    def test_no_new_tags(self):
+        pass
+
+    @tag('baz')
+    def test_new_func_tag(self):
+        pass
+
+
+@tag('bar')
+class FooBar(FooBase):
+
+    def test_new_class_tag_only(self):
+        pass
+
+    @tag('baz')
+    def test_new_class_and_func_tags(self):
+        pass