298 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			298 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Python
		
	
	
	
| """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
 |