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:
parent
f472f21406
commit
627e068516
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue