conftest.py
files are directory-level (read "package") configurations. So if you put one at the root directory of your tests, its session-scoped fixtures will run at the beginning of that scope and the corresponding tear_down
will wait for the scope's conclusion (i.e. the entire test session) before executing. If you need to create fixtures that span only sub-directories (sub-packages), you need to put additional conftest.py
files at those levels (with their own scope='session'
fixtures). A common example is to add data to a database. Imagine wanting to populate your purchases
db table with some rows for all your tests inside the corresponding test package. You'd place the fixture that does the job inside tests.purchases.conftest.py
.
shopping_app/
tests/
__init__.py
conftest.py # applies to all tests
buyers/
products/
purchases/
conftest.py # only applies to this scope and sub-scopes
__init__.py
test1.py
test2.py
payments/
refunds/
sellers/
stores/
And inside tests.purchases.conftest.py
you'd have ordinary fixture declarations. For instance a set_up/tear_down combo to prepopulate and delete rows for your db table would looks something like this:
@pytest.fixture(scope='session', autouse=True)
def prep_purchases(db, data):
# set_up: fill table at beginning of scope
populate_purchase_table_with_data(db, data)
# yield, to let all tests within the scope run
yield
# tear_down: then clear table at the end of the scope
empty_purchase_table(db)
Some fixtures do not need to be explicitly injected into tests (we're only interested by their side-effect, not their return value), hence the autouse
parameter. As for the context manager syntax for set_up/tear_down (with yield
), if you're not comfortable with it, you can alternatively place the tear_down
part as its own separate function.