diff --git a/_pytest/compat.py b/_pytest/compat.py index 54271ce4f40..255f69ce0d8 100644 --- a/_pytest/compat.py +++ b/_pytest/compat.py @@ -83,7 +83,15 @@ def num_mock_patch_args(function): return len(patchings) -def getfuncargnames(function, startindex=None): +def getfuncargnames(function, startindex=None, cls=None): + """ + @RonnyPfannschmidt: This function should be refactored when we revisit fixtures. The + fixture mechanism should ask the node for the fixture names, and not try to obtain + directly from the function object well after collection has occurred. + """ + if startindex is None and cls is not None: + is_staticmethod = isinstance(cls.__dict__.get(function.__name__, None), staticmethod) + startindex = 0 if is_staticmethod else 1 # XXX merge with main.py's varnames # assert not isclass(function) realfunction = function diff --git a/_pytest/fixtures.py b/_pytest/fixtures.py index 4386500f4e4..f57031e1ad0 100644 --- a/_pytest/fixtures.py +++ b/_pytest/fixtures.py @@ -957,11 +957,7 @@ def __init__(self, session): def getfixtureinfo(self, node, func, cls, funcargs=True): if funcargs and not hasattr(node, "nofuncargs"): - if cls is not None: - startindex = 1 - else: - startindex = None - argnames = getfuncargnames(func, startindex) + argnames = getfuncargnames(func, cls=cls) else: argnames = () usefixtures = getattr(func, "usefixtures", None) diff --git a/changelog/2699.bugfix b/changelog/2699.bugfix new file mode 100644 index 00000000000..c5e07329bc0 --- /dev/null +++ b/changelog/2699.bugfix @@ -0,0 +1 @@ +Allow tests declared as ``@staticmethod`` to use fixtures. diff --git a/testing/python/collect.py b/testing/python/collect.py index bd7013b4488..b24c0b2fd9d 100644 --- a/testing/python/collect.py +++ b/testing/python/collect.py @@ -147,11 +147,21 @@ class test(object): ]) def test_static_method(self, testdir): + """Support for collecting staticmethod tests (#2528, #2699)""" testdir.getmodulecol(""" + import pytest class Test(object): @staticmethod def test_something(): pass + + @pytest.fixture + def fix(self): + return 1 + + @staticmethod + def test_fix(fix): + assert fix == 1 """) result = testdir.runpytest() if sys.version_info < (2, 7): @@ -162,8 +172,8 @@ def test_something(): ]) else: result.stdout.fnmatch_lines([ - "*collected 1 item*", - "*1 passed in*", + "*collected 2 items*", + "*2 passed in*", ]) def test_setup_teardown_class_as_classmethod(self, testdir): diff --git a/testing/python/fixture.py b/testing/python/fixture.py index f8aef802fa4..06b08d68eea 100644 --- a/testing/python/fixture.py +++ b/testing/python/fixture.py @@ -29,10 +29,16 @@ class A(object): def f(self, arg1, arg2="hello"): pass + @staticmethod + def static(arg1, arg2): + pass + assert fixtures.getfuncargnames(A().f) == ('arg1',) if sys.version_info < (3, 0): assert fixtures.getfuncargnames(A.f) == ('arg1',) + assert fixtures.getfuncargnames(A.static, cls=A) == ('arg1', 'arg2') + class TestFillFixtures(object): def test_fillfuncargs_exposed(self):