From c3d734054241f69220070ce6d4cb00db4acc50c6 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 31 Jan 2019 20:24:11 -0200 Subject: [PATCH] Fix setUpClass being called in subclasses that were skipped Fix #4700 --- changelog/4700.bugfix.rst | 2 ++ src/_pytest/unittest.py | 3 +++ .../example_scripts/unittest/test_setup_skip.py | 13 +++++++++++++ .../unittest/test_setup_skip_class.py | 14 ++++++++++++++ .../unittest/test_setup_skip_module.py | 12 ++++++++++++ testing/test_unittest.py | 15 +++++++++++++++ 6 files changed, 59 insertions(+) create mode 100644 changelog/4700.bugfix.rst create mode 100644 testing/example_scripts/unittest/test_setup_skip.py create mode 100644 testing/example_scripts/unittest/test_setup_skip_class.py create mode 100644 testing/example_scripts/unittest/test_setup_skip_module.py diff --git a/changelog/4700.bugfix.rst b/changelog/4700.bugfix.rst new file mode 100644 index 000000000..3f8acb876 --- /dev/null +++ b/changelog/4700.bugfix.rst @@ -0,0 +1,2 @@ +Fix regression where ``setUpClass`` would always be called in subclasses even if all tests +were skipped by a ``unittest.skip()`` decorator applied in the subclass. diff --git a/src/_pytest/unittest.py b/src/_pytest/unittest.py index e00636d46..58d79845b 100644 --- a/src/_pytest/unittest.py +++ b/src/_pytest/unittest.py @@ -87,6 +87,9 @@ def _make_xunit_fixture(obj, setup_name, teardown_name, scope, pass_self): @pytest.fixture(scope=scope, autouse=True) def fixture(self, request): + if getattr(self, "__unittest_skip__", None): + reason = self.__unittest_skip_why__ + pytest.skip(reason) if setup is not None: if pass_self: setup(self, request.function) diff --git a/testing/example_scripts/unittest/test_setup_skip.py b/testing/example_scripts/unittest/test_setup_skip.py new file mode 100644 index 000000000..93f79bb3b --- /dev/null +++ b/testing/example_scripts/unittest/test_setup_skip.py @@ -0,0 +1,13 @@ +"""Skipping an entire subclass with unittest.skip() should *not* call setUp from a base class.""" +import unittest + + +class Base(unittest.TestCase): + def setUp(self): + assert 0 + + +@unittest.skip("skip all tests") +class Test(Base): + def test_foo(self): + assert 0 diff --git a/testing/example_scripts/unittest/test_setup_skip_class.py b/testing/example_scripts/unittest/test_setup_skip_class.py new file mode 100644 index 000000000..4f251dcba --- /dev/null +++ b/testing/example_scripts/unittest/test_setup_skip_class.py @@ -0,0 +1,14 @@ +"""Skipping an entire subclass with unittest.skip() should *not* call setUpClass from a base class.""" +import unittest + + +class Base(unittest.TestCase): + @classmethod + def setUpClass(cls): + assert 0 + + +@unittest.skip("skip all tests") +class Test(Base): + def test_foo(self): + assert 0 diff --git a/testing/example_scripts/unittest/test_setup_skip_module.py b/testing/example_scripts/unittest/test_setup_skip_module.py new file mode 100644 index 000000000..98befbe51 --- /dev/null +++ b/testing/example_scripts/unittest/test_setup_skip_module.py @@ -0,0 +1,12 @@ +"""setUpModule is always called, even if all tests in the module are skipped""" +import unittest + + +def setUpModule(): + assert 0 + + +@unittest.skip("skip all tests") +class Base(unittest.TestCase): + def test(self): + assert 0 diff --git a/testing/test_unittest.py b/testing/test_unittest.py index 2c60cd271..fe33855fa 100644 --- a/testing/test_unittest.py +++ b/testing/test_unittest.py @@ -1026,3 +1026,18 @@ def test_error_message_with_parametrized_fixtures(testdir): "*Function type: TestCaseFunction", ] ) + + +@pytest.mark.parametrize( + "test_name, expected_outcome", + [ + ("test_setup_skip.py", "1 skipped"), + ("test_setup_skip_class.py", "1 skipped"), + ("test_setup_skip_module.py", "1 error"), + ], +) +def test_setup_inheritance_skipping(testdir, test_name, expected_outcome): + """Issue #4700""" + testdir.copy_example("unittest/{}".format(test_name)) + result = testdir.runpytest() + result.stdout.fnmatch_lines("* {} in *".format(expected_outcome))