From 9b9fede5beef291887853ebf0d4c2cc60f6fbfc2 Mon Sep 17 00:00:00 2001 From: Nathaniel Waisbrot Date: Sun, 25 Jun 2017 13:56:50 -0400 Subject: [PATCH] allow staticmethods to be detected as test functions Allow a class method decorated `@staticmethod` to be collected as a test function (if it meets the usual criteria). This feature will not work in Python 2.6 -- static methods will still be ignored there. --- AUTHORS | 1 + _pytest/python.py | 17 +++++++++++++---- changelog/2528.feature | 1 + testing/python/collect.py | 20 ++++++++++++++++++++ 4 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 changelog/2528.feature diff --git a/AUTHORS b/AUTHORS index ca282870f..2fd164470 100644 --- a/AUTHORS +++ b/AUTHORS @@ -118,6 +118,7 @@ Michael Droettboom Michael Seifert Michal Wajszczuk Mike Lundy +Nathaniel Waisbrot Ned Batchelder Neven Mundar Nicolas Delaby diff --git a/_pytest/python.py b/_pytest/python.py index e10282a8c..3750f61da 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -271,10 +271,19 @@ class PyCollector(PyobjMixin, main.Collector): return self._matches_prefix_or_glob_option('python_classes', name) def istestfunction(self, obj, name): - return ( - (self.funcnamefilter(name) or self.isnosetest(obj)) and - safe_getattr(obj, "__call__", False) and fixtures.getfixturemarker(obj) is None - ) + if self.funcnamefilter(name) or self.isnosetest(obj): + if isinstance(obj, staticmethod): + # static methods need to be unwrapped + obj = safe_getattr(obj, '__func__', False) + if obj is False: + # Python 2.6 wraps in a different way that we won't try to handle + self.warn(code="C2", message="cannot collect static method %r because it is not a function (always the case in Python 2.6)" % name) + return False + return ( + safe_getattr(obj, "__call__", False) and fixtures.getfixturemarker(obj) is None + ) + else: + return False def istestclass(self, obj, name): return self.classnamefilter(name) or self.isnosetest(obj) diff --git a/changelog/2528.feature b/changelog/2528.feature new file mode 100644 index 000000000..c91cdb5d7 --- /dev/null +++ b/changelog/2528.feature @@ -0,0 +1 @@ +Allow class methods decorated as ``@staticmethod`` to be candidates for collection as a test function. (Only for Python 2.7 and above. Python 2.6 will still ignore static methods.) diff --git a/testing/python/collect.py b/testing/python/collect.py index 236421f1c..1b62fb770 100644 --- a/testing/python/collect.py +++ b/testing/python/collect.py @@ -143,6 +143,26 @@ class TestClass(object): "*collected 0*", ]) + def test_static_method(self, testdir): + testdir.getmodulecol(""" + class Test(object): + @staticmethod + def test_something(): + pass + """) + result = testdir.runpytest() + if sys.version_info < (2,7): + # in 2.6, the code to handle static methods doesn't work + result.stdout.fnmatch_lines([ + "*collected 0 items*", + "*cannot collect static method*", + ]) + else: + result.stdout.fnmatch_lines([ + "*collected 1 item*", + "*1 passed in*", + ]) + def test_setup_teardown_class_as_classmethod(self, testdir): testdir.makepyfile(test_mod1=""" class TestClassMethod(object):