fix issue172 so that @pytest.setup marked setup_module/function... functions

are not called twice.  Also fix ordering to that broader scoped setup
functions are executed first.
This commit is contained in:
holger krekel 2012-08-13 13:37:14 +02:00
parent f472f21406
commit 627e068516
3 changed files with 76 additions and 12 deletions

View File

@ -1,6 +1,8 @@
Changes between 2.2.4 and 2.3.0.dev
-----------------------------------
- fix issue172 duplicate call of pytest.setup-decoratored setup_module
functions
- fix junitxml=path construction so that if tests change the
current working directory and the path is a relative path
it is constructed correctly from the original current working dir.

View File

@ -363,24 +363,26 @@ class Module(pytest.File, PyCollector):
return mod
def setup(self):
if hasattr(self.obj, 'setup_module'):
setup_module = xunitsetup(self.obj, "setup_module")
if setup_module is not None:
#XXX: nose compat hack, move to nose plugin
# if it takes a positional arg, its probably a pytest style one
# so we pass the current module object
if inspect.getargspec(self.obj.setup_module)[0]:
self.obj.setup_module(self.obj)
if inspect.getargspec(setup_module)[0]:
setup_module(self.obj)
else:
self.obj.setup_module()
setup_module()
def teardown(self):
if hasattr(self.obj, 'teardown_module'):
teardown_module = xunitsetup(self.obj, 'teardown_module')
if teardown_module is not None:
#XXX: nose compat hack, move to nose plugin
# if it takes a positional arg, its probably a py.test style one
# so we pass the current module object
if inspect.getargspec(self.obj.teardown_module)[0]:
self.obj.teardown_module(self.obj)
if inspect.getargspec(teardown_module)[0]:
teardown_module(self.obj)
else:
self.obj.teardown_module()
teardown_module()
class Class(PyCollector):
""" Collector for test methods. """
@ -388,14 +390,14 @@ class Class(PyCollector):
return [self._getcustomclass("Instance")(name="()", parent=self)]
def setup(self):
setup_class = getattr(self.obj, 'setup_class', None)
setup_class = xunitsetup(self.obj, 'setup_class')
if setup_class is not None:
setup_class = getattr(setup_class, 'im_func', setup_class)
setup_class = getattr(setup_class, '__func__', setup_class)
setup_class(self.obj)
def teardown(self):
teardown_class = getattr(self.obj, 'teardown_class', None)
teardown_class = xunitsetup(self.obj, 'teardown_class')
if teardown_class is not None:
teardown_class = getattr(teardown_class, 'im_func', teardown_class)
teardown_class = getattr(teardown_class, '__func__', teardown_class)
@ -431,7 +433,7 @@ class FunctionMixin(PyobjMixin):
name = 'setup_method'
else:
name = 'setup_function'
setup_func_or_method = getattr(obj, name, None)
setup_func_or_method = xunitsetup(obj, name)
if setup_func_or_method is not None:
setup_func_or_method(self.obj)
@ -442,7 +444,7 @@ class FunctionMixin(PyobjMixin):
else:
name = 'teardown_function'
obj = self.parent.obj
teardown_func_or_meth = getattr(obj, name, None)
teardown_func_or_meth = xunitsetup(obj, name)
if teardown_func_or_meth is not None:
teardown_func_or_meth(self.obj)
@ -1338,6 +1340,7 @@ class FuncargManager:
if nodeid.startswith(setupcall.baseid):
l.append(setupcall)
allargnames.update(setupcall.funcargnames)
l.sort(key=lambda x: x.scopenum)
return l, allargnames
@ -1479,6 +1482,7 @@ class SetupCall:
self.func = func
self.funcargnames = getfuncargnames(func)
self.scope = scope
self.scopenum = scopes.index(scope)
self.active = False
self._finalizer = []
@ -1595,3 +1599,9 @@ def getfuncargparams(item, ignore, scopenum, cache):
# argparams.append(key)
return argparams
def xunitsetup(obj, name):
meth = getattr(obj, name, None)
if meth is not None:
if not hasattr(meth, "_pytestsetup"):
return meth

View File

@ -1874,6 +1874,28 @@ class TestSetupManagement:
l = config._conftest.getconftestmodules(p)[0].l
assert l == ["fin_a1", "fin_a2", "fin_b1", "fin_b2"] * 2
def test_setup_scope_ordering(self, testdir):
testdir.makepyfile("""
import pytest
l = []
@pytest.setup(scope="function")
def fappend2():
l.append(2)
@pytest.setup(scope="class")
def classappend3():
l.append(3)
@pytest.setup(scope="module")
def mappend():
l.append(1)
class TestHallo:
def test_method(self):
assert l == [1,3,2]
""")
reprec = testdir.inline_run()
reprec.assertoutcome(passed=1)
class TestFuncargMarker:
def test_parametrize(self, testdir):
testdir.makepyfile("""
@ -2404,3 +2426,33 @@ class TestTestContextVarious:
""")
reprec = testdir.inline_run()
reprec.assertoutcome(passed=2)
def test_setupdecorator_and_xunit(testdir):
testdir.makepyfile("""
import pytest
l = []
@pytest.setup(scope='module')
def setup_module():
l.append("module")
@pytest.setup()
def setup_function():
l.append("function")
def test_func():
pass
class TestClass:
@pytest.setup(scope="class")
def setup_class(self):
l.append("class")
@pytest.setup()
def setup_method(self):
l.append("method")
def test_method(self):
pass
def test_all():
assert l == ["module", "function", "class",
"function", "method", "function"]
""")
reprec = testdir.inline_run()
reprec.assertoutcome(passed=3)