Fixtures
You can use autouse fixtures also for method-level setup/teardown. I would prefer using fixtures because of their flexibility - you can define class-specific method setup/teardown (running for every test method) or method-specific setup/teardown (running for a speficic test only) if/when needed. Examples:
import pytest
class TestFoo:
@pytest.fixture(autouse=True)
def foo(self):
print('\nTestFoo instance setting up')
yield
print('TestFoo instance tearing down')
class TestBar(TestFoo):
@pytest.fixture(autouse=True)
def bar(self, foo):
print('TestBar instance setting up')
yield
print('TestBar instance tearing down')
class TestBaz(TestBar):
@pytest.fixture(autouse=True)
def baz(self, bar):
print('TestBaz instance setting up')
yield
print('\nTestBaz instance tearing down')
def test_eggs(self):
assert True
def test_bacon(self):
assert True
Test execution yields:
collected 2 items
test_spam.py::TestBaz::test_eggs
TestFoo instance setting up
TestBar instance setting up
TestBaz instance setting up
PASSED
TestBaz instance tearing down
TestBar instance tearing down
TestFoo instance tearing down
test_spam.py::TestBaz::test_bacon
TestFoo instance setting up
TestBar instance setting up
TestBaz instance setting up
PASSED
TestBaz instance tearing down
TestBar instance tearing down
TestFoo instance tearing down
Notice that I specify fixture execution order via arg dependencies (e.g. def bar(self, foo):
so bar
is executed after foo
); if you omit the arguments, the execution order foo -> bar -> baz
is not guaranteed. If you don't need the explicit ordering, you can safely omit the fixture args.
The above example, extended with a setup/teardown specific for TestBaz::test_bacon
only:
class TestBaz(TestBar):
@pytest.fixture(autouse=True)
def baz(self, bar):
print('TestBaz instance setting up')
yield
print('\nTestBaz instance tearing down')
@pytest.fixture
def bacon_specific(self):
print('bacon specific test setup')
yield
print('\nbacon specific teardown')
def test_eggs(self):
assert True
@pytest.mark.usefixtures('bacon_specific')
def test_bacon(self):
assert True
Execution yields:
...
test_spam.py::TestBaz::test_bacon
TestFoo instance setting up
TestBar instance setting up
TestBaz instance setting up
bacon specific test setup
PASSED
bacon specific teardown
TestBaz instance tearing down
TestBar instance tearing down
TestFoo instance tearing down
One-time setup/teardown per class is achieved by adjusting the fixture scope to class
:
class TestFoo:
@pytest.fixture(autouse=True, scope='class')
def foo(self):
print('\nTestFoo instance setting up')
yield
print('TestFoo instance tearing down')
class TestBar(TestFoo):
@pytest.fixture(autouse=True, scope='class')
def bar(self, foo):
print('TestBar instance setting up')
yield
print('TestBar instance tearing down')
class TestBaz(TestBar):
@pytest.fixture(autouse=True, scope='class')
def baz(self, bar):
print('TestBaz instance setting up')
yield
print('\nTestBaz instance tearing down')
def test_eggs(self):
assert True
def test_bacon(self):
assert True
Execution:
collected 2 items
test_spam2.py::TestBaz::test_eggs
TestFoo instance setting up
TestBar instance setting up
TestBaz instance setting up
PASSED
test_spam2.py::TestBaz::test_bacon PASSED
TestBaz instance tearing down
TestBar instance tearing down
TestFoo instance tearing down
xUnit method setup/teardown
You can use the xUnit-style setup, in particular the Method and function level setup/teardown; these are usual class methods and support inheritance. Example:
class TestFoo:
def setup_method(self):
print('\nTestFoo::setup_method called')
def teardown_method(self):
print('TestFoo::teardown_method called')
class TestBar(TestFoo):
def setup_method(self):
super().setup_method()
print('TestBar::setup_method called')
def teardown_method(self):
print('TestBar::teardown_method called')
super().teardown_method()
class TestBaz(TestBar):
def setup_method(self):
super().setup_method()
print('TestBaz::setup_method called')
def teardown_method(self):
print('\nTestBaz::teardown_method called')
super().teardown_method()
def test_eggs(self):
assert True
def test_bacon(self):
assert True
Test execution yields:
collected 2 items
test_spam.py::TestBaz::test_eggs
TestFoo::setup_method called
TestBar::setup_method called
TestBaz::setup_method called
PASSED
TestBaz::teardown_method called
TestBar::teardown_method called
TestFoo::teardown_method called
test_spam.py::TestBaz::test_bacon
TestFoo::setup_method called
TestBar::setup_method called
TestBaz::setup_method called
PASSED
TestBaz::teardown_method called
TestBar::teardown_method called
TestFoo::teardown_method called