From 8de2c035e2ef2ac3348e2ba9da2c957dbd8ede50 Mon Sep 17 00:00:00 2001 From: LeeKamentsky Date: Wed, 4 Nov 2015 13:52:40 -0500 Subject: [PATCH 1/5] Fixes #1169 The unittest.skip decorator runs @functools.wraps on self._testcase. functools.wraps expects a "__name__" attribute and this patch adds one. It might not be the correct fix, but it works for me. --- _pytest/unittest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/_pytest/unittest.py b/_pytest/unittest.py index 3b08c9f90..6c3a72697 100644 --- a/_pytest/unittest.py +++ b/_pytest/unittest.py @@ -134,6 +134,7 @@ class TestCaseFunction(pytest.Function): pass def runtest(self): + setattr(self._testcase, "__name__", self.name) self._testcase(result=self) def _prunetraceback(self, excinfo): From 18335479369e84ce20792ec747bc260556830c28 Mon Sep 17 00:00:00 2001 From: Lee Kamentsky Date: Wed, 4 Nov 2015 14:24:22 -0500 Subject: [PATCH 2/5] Added test for issue #1169 (I undid my fix, checked for failure, redid my fix and it passes) --- testing/test_unittest.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/testing/test_unittest.py b/testing/test_unittest.py index aa055f89c..287b8d3ac 100644 --- a/testing/test_unittest.py +++ b/testing/test_unittest.py @@ -718,3 +718,16 @@ def test_unittest_raise_skip_issue748(testdir): *SKIP*[1]*test_foo.py*skipping due to reasons* *1 skipped* """) + +def test_unittest_skip_issue1169(testdir): + testpath = testdir.makepyfile(test_foo=""" + import unittest + + class MyTestCase(unittest.TestCase): + @unittest.skip + def test_skip(self): + self.fail() + """) + reprec = testdir.inline_run(testpath) + reprec.assertoutcome(passed=1) + \ No newline at end of file From 313050b15b20a510edb1bce15deff25b514ef4e6 Mon Sep 17 00:00:00 2001 From: Lee Kamentsky Date: Wed, 4 Nov 2015 15:30:16 -0500 Subject: [PATCH 3/5] Suggested edits by Bruno. Moved fix to TestCaseFunction.setup. Added myself to AUTHORS and added entry to CHANGELOG --- AUTHORS | 1 + CHANGELOG | 3 +++ _pytest/unittest.py | 11 ++++++++++- testing/test_unittest.py | 1 + 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 27df00fc6..641e20441 100644 --- a/AUTHORS +++ b/AUTHORS @@ -46,6 +46,7 @@ Jason R. Coombs Jurko Gospodnetić Katarzyna Jachim Kevin Cox +Lee Kamentsky Maciek Fijalkowski Maho Marc Schlaich diff --git a/CHANGELOG b/CHANGELOG index 3e254d34f..4be7212a6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,9 @@ 2.8.3.dev --------- +- fix #1169: add __name__ attribute to testcases in TestCaseFunction to + support the @unittest.skip decorator on functions and methods. + - fix #1035: collecting tests if test module level obj has __getattr__(). Thanks Suor for the report and Bruno Oliveira / Tom Viner for the PR. diff --git a/_pytest/unittest.py b/_pytest/unittest.py index 6c3a72697..1292c2a93 100644 --- a/_pytest/unittest.py +++ b/_pytest/unittest.py @@ -69,6 +69,16 @@ class TestCaseFunction(pytest.Function): def setup(self): self._testcase = self.parent.obj(self.name) + # + # See issue #1169 + # + # The @unittest.skip decorator calls functools.wraps(self._testcase) + # The call to functools.wraps() fails unless self._testcase + # has a __name__ attribute. This is usually automatically supplied + # if the test is a function or method, but we need to add manually + # here. + # + setattr(self._testcase, "__name__", self.name) self._obj = getattr(self._testcase, self.name) if hasattr(self._testcase, 'setup_method'): self._testcase.setup_method(self._obj) @@ -134,7 +144,6 @@ class TestCaseFunction(pytest.Function): pass def runtest(self): - setattr(self._testcase, "__name__", self.name) self._testcase(result=self) def _prunetraceback(self, excinfo): diff --git a/testing/test_unittest.py b/testing/test_unittest.py index 287b8d3ac..3ff90d058 100644 --- a/testing/test_unittest.py +++ b/testing/test_unittest.py @@ -719,6 +719,7 @@ def test_unittest_raise_skip_issue748(testdir): *1 skipped* """) +@pytest.mark.skipif("sys.version_info < (2,7)") def test_unittest_skip_issue1169(testdir): testpath = testdir.makepyfile(test_foo=""" import unittest From 7d6edb9ca57945cd42922e6c499ba510598dbff4 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 4 Nov 2015 19:54:18 -0200 Subject: [PATCH 4/5] Fix unittest.skip decorator test and separate the fix into a different, self-doc function --- _pytest/unittest.py | 24 ++++++++++++++---------- testing/test_unittest.py | 12 +++++++----- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/_pytest/unittest.py b/_pytest/unittest.py index 1292c2a93..bb7579331 100644 --- a/_pytest/unittest.py +++ b/_pytest/unittest.py @@ -69,22 +69,26 @@ class TestCaseFunction(pytest.Function): def setup(self): self._testcase = self.parent.obj(self.name) - # - # See issue #1169 - # - # The @unittest.skip decorator calls functools.wraps(self._testcase) - # The call to functools.wraps() fails unless self._testcase - # has a __name__ attribute. This is usually automatically supplied - # if the test is a function or method, but we need to add manually - # here. - # - setattr(self._testcase, "__name__", self.name) + self._fix_unittest_skip_decorator() self._obj = getattr(self._testcase, self.name) if hasattr(self._testcase, 'setup_method'): self._testcase.setup_method(self._obj) if hasattr(self, "_request"): self._request._fillfixtures() + def _fix_unittest_skip_decorator(self): + """ + The @unittest.skip decorator calls functools.wraps(self._testcase) + The call to functools.wraps() fails unless self._testcase + has a __name__ attribute. This is usually automatically supplied + if the test is a function or method, but we need to add manually + here. + + See issue #1169 + """ + if sys.version_info[0] == 2: + setattr(self._testcase, "__name__", self.name) + def teardown(self): if hasattr(self._testcase, 'teardown_method'): self._testcase.teardown_method(self._obj) diff --git a/testing/test_unittest.py b/testing/test_unittest.py index 3ff90d058..53dde6ea3 100644 --- a/testing/test_unittest.py +++ b/testing/test_unittest.py @@ -721,14 +721,16 @@ def test_unittest_raise_skip_issue748(testdir): @pytest.mark.skipif("sys.version_info < (2,7)") def test_unittest_skip_issue1169(testdir): - testpath = testdir.makepyfile(test_foo=""" + testdir.makepyfile(test_foo=""" import unittest class MyTestCase(unittest.TestCase): - @unittest.skip + @unittest.skip("skipping due to reasons") def test_skip(self): self.fail() """) - reprec = testdir.inline_run(testpath) - reprec.assertoutcome(passed=1) - \ No newline at end of file + result = testdir.runpytest("-v", '-rs') + result.stdout.fnmatch_lines(""" + *SKIP*[1]*skipping due to reasons* + *1 skipped* + """) From a7a470b56f1e7045d2136e3d62e2790f8bac7852 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 4 Nov 2015 19:55:05 -0200 Subject: [PATCH 5/5] Give credit where it is due --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 4be7212a6..0957af637 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,7 @@ - fix #1169: add __name__ attribute to testcases in TestCaseFunction to support the @unittest.skip decorator on functions and methods. + Thanks Lee Kamentsky for the PR. - fix #1035: collecting tests if test module level obj has __getattr__(). Thanks Suor for the report and Bruno Oliveira / Tom Viner for the PR.