Source code

Revision control

Copy as Markdown

Other Tools

"""Test correct setup/teardowns at module, class, and instance level."""
from typing import List
import pytest
from _pytest.pytester import Pytester
def test_module_and_function_setup(pytester: Pytester) -> None:
reprec = pytester.inline_runsource(
"""
modlevel = []
def setup_module(module):
assert not modlevel
module.modlevel.append(42)
def teardown_module(module):
modlevel.pop()
def setup_function(function):
function.answer = 17
def teardown_function(function):
del function.answer
def test_modlevel():
assert modlevel[0] == 42
assert test_modlevel.answer == 17
class TestFromClass(object):
def test_module(self):
assert modlevel[0] == 42
assert not hasattr(test_modlevel, 'answer')
"""
)
rep = reprec.matchreport("test_modlevel")
assert rep.passed
rep = reprec.matchreport("test_module")
assert rep.passed
def test_module_setup_failure_no_teardown(pytester: Pytester) -> None:
reprec = pytester.inline_runsource(
"""
values = []
def setup_module(module):
values.append(1)
0/0
def test_nothing():
pass
def teardown_module(module):
values.append(2)
"""
)
reprec.assertoutcome(failed=1)
calls = reprec.getcalls("pytest_runtest_setup")
assert calls[0].item.module.values == [1]
def test_setup_function_failure_no_teardown(pytester: Pytester) -> None:
reprec = pytester.inline_runsource(
"""
modlevel = []
def setup_function(function):
modlevel.append(1)
0/0
def teardown_function(module):
modlevel.append(2)
def test_func():
pass
"""
)
calls = reprec.getcalls("pytest_runtest_setup")
assert calls[0].item.module.modlevel == [1]
def test_class_setup(pytester: Pytester) -> None:
reprec = pytester.inline_runsource(
"""
class TestSimpleClassSetup(object):
clslevel = []
def setup_class(cls):
cls.clslevel.append(23)
def teardown_class(cls):
cls.clslevel.pop()
def test_classlevel(self):
assert self.clslevel[0] == 23
class TestInheritedClassSetupStillWorks(TestSimpleClassSetup):
def test_classlevel_anothertime(self):
assert self.clslevel == [23]
def test_cleanup():
assert not TestSimpleClassSetup.clslevel
assert not TestInheritedClassSetupStillWorks.clslevel
"""
)
reprec.assertoutcome(passed=1 + 2 + 1)
def test_class_setup_failure_no_teardown(pytester: Pytester) -> None:
reprec = pytester.inline_runsource(
"""
class TestSimpleClassSetup(object):
clslevel = []
def setup_class(cls):
0/0
def teardown_class(cls):
cls.clslevel.append(1)
def test_classlevel(self):
pass
def test_cleanup():
assert not TestSimpleClassSetup.clslevel
"""
)
reprec.assertoutcome(failed=1, passed=1)
def test_method_setup(pytester: Pytester) -> None:
reprec = pytester.inline_runsource(
"""
class TestSetupMethod(object):
def setup_method(self, meth):
self.methsetup = meth
def teardown_method(self, meth):
del self.methsetup
def test_some(self):
assert self.methsetup == self.test_some
def test_other(self):
assert self.methsetup == self.test_other
"""
)
reprec.assertoutcome(passed=2)
def test_method_setup_failure_no_teardown(pytester: Pytester) -> None:
reprec = pytester.inline_runsource(
"""
class TestMethodSetup(object):
clslevel = []
def setup_method(self, method):
self.clslevel.append(1)
0/0
def teardown_method(self, method):
self.clslevel.append(2)
def test_method(self):
pass
def test_cleanup():
assert TestMethodSetup.clslevel == [1]
"""
)
reprec.assertoutcome(failed=1, passed=1)
def test_method_setup_uses_fresh_instances(pytester: Pytester) -> None:
reprec = pytester.inline_runsource(
"""
class TestSelfState1(object):
memory = []
def test_hello(self):
self.memory.append(self)
def test_afterhello(self):
assert self != self.memory[0]
"""
)
reprec.assertoutcome(passed=2, failed=0)
def test_setup_that_skips_calledagain(pytester: Pytester) -> None:
p = pytester.makepyfile(
"""
import pytest
def setup_module(mod):
pytest.skip("x")
def test_function1():
pass
def test_function2():
pass
"""
)
reprec = pytester.inline_run(p)
reprec.assertoutcome(skipped=2)
def test_setup_fails_again_on_all_tests(pytester: Pytester) -> None:
p = pytester.makepyfile(
"""
import pytest
def setup_module(mod):
raise ValueError(42)
def test_function1():
pass
def test_function2():
pass
"""
)
reprec = pytester.inline_run(p)
reprec.assertoutcome(failed=2)
def test_setup_funcarg_setup_when_outer_scope_fails(pytester: Pytester) -> None:
p = pytester.makepyfile(
"""
import pytest
def setup_module(mod):
raise ValueError(42)
@pytest.fixture
def hello(request):
raise ValueError("xyz43")
def test_function1(hello):
pass
def test_function2(hello):
pass
"""
)
result = pytester.runpytest(p)
result.stdout.fnmatch_lines(
[
"*function1*",
"*ValueError*42*",
"*function2*",
"*ValueError*42*",
"*2 errors*",
]
)
result.stdout.no_fnmatch_line("*xyz43*")
@pytest.mark.parametrize("arg", ["", "arg"])
def test_setup_teardown_function_level_with_optional_argument(
pytester: Pytester,
monkeypatch,
arg: str,
) -> None:
"""Parameter to setup/teardown xunit-style functions parameter is now optional (#1728)."""
import sys
trace_setups_teardowns: List[str] = []
monkeypatch.setattr(
sys, "trace_setups_teardowns", trace_setups_teardowns, raising=False
)
p = pytester.makepyfile(
"""
import pytest
import sys
trace = sys.trace_setups_teardowns.append
def setup_module({arg}): trace('setup_module')
def teardown_module({arg}): trace('teardown_module')
def setup_function({arg}): trace('setup_function')
def teardown_function({arg}): trace('teardown_function')
def test_function_1(): pass
def test_function_2(): pass
class Test(object):
def setup_method(self, {arg}): trace('setup_method')
def teardown_method(self, {arg}): trace('teardown_method')
def test_method_1(self): pass
def test_method_2(self): pass
""".format(
arg=arg
)
)
result = pytester.inline_run(p)
result.assertoutcome(passed=4)
expected = [
"setup_module",
"setup_function",
"teardown_function",
"setup_function",
"teardown_function",
"setup_method",
"teardown_method",
"setup_method",
"teardown_method",
"teardown_module",
]
assert trace_setups_teardowns == expected