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.
This commit is contained in:
Nathaniel Waisbrot 2017-06-25 13:56:50 -04:00
parent 9b51fc646c
commit 9b9fede5be
No known key found for this signature in database
GPG Key ID: 75FFF87BD3EEA0CA
4 changed files with 35 additions and 4 deletions

View File

@ -118,6 +118,7 @@ Michael Droettboom
Michael Seifert
Michal Wajszczuk
Mike Lundy
Nathaniel Waisbrot
Ned Batchelder
Neven Mundar
Nicolas Delaby

View File

@ -271,10 +271,19 @@ class PyCollector(PyobjMixin, main.Collector):
return self._matches_prefix_or_glob_option('python_classes', name)
def istestfunction(self, obj, name):
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 (
(self.funcnamefilter(name) or self.isnosetest(obj)) and
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)

1
changelog/2528.feature Normal file
View File

@ -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.)

View File

@ -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):