
Pytest — Fixture Scope
This post will cover what fixture scopes are within pytest and why you should use them. When developing with a large pytest test suite or using large, time-consuming fixtures, setting the correct fixture scope can shave considerable time off your test duration.
What is fixture scope?
Fixture scope allows you to configure the ‘scope’, or lifetime, of a fixture. It’s set by passing the scope parameter on the creation of a fixture.
@pytest.fixture(scope="module")
def my_fixture():
passThe available scopes are:
session: The fixture is destroyed at the end of the test session.package: The fixture is destroyed during teardown of the last test in a package.module: The fixture is destroyed during teardown of the last test in a module.class: The fixture is destroyed during teardown of the last test in a class.function: The fixture is destroyed at the end of each test.
The default scope, if not specified, is function. The most time-intensive.
Leveraging Fixture Scope
If you have a heavy-duty fixture, for example, establishing a network connection, generating large test data or doing I/O operations, setting the incorrect scope can significantly slow down your test suite.
If you know a fixture will be re-used throughout your tests, then set it to have the session scope or a different appropriate scope depending on its use. If it’s used throughout a class, then set the class scope etc. It will be created once and reused for each test it’s requested for. Rather than the default, which will be to create and destroy it for every test it’s used in.
Personal Example
I have a pytest suite for a personal project with around 450 tests utilising around 60 different fixtures. If I run this, using no parallelisation, and using the default fixture scope of function for all the fixtures, the tests take a total of 3 minutes 42 seconds.
452 passed, 4 skipped, 27 warnings, 25 subtests passed in 222.85s (0:03:42)Ignore the warnings, I’ll get around to them eventually…
However, if I configure a correct and sensible scope for all my fixtures, the time drops to just under 3 minutes.
452 passed, 4 skipped, 27 warnings, 25 subtests passed in 173.67s (0:02:53)That’s over a 20% reduction in time. Not bad for adding one parameter.
I had fixtures that were reading large amounts of OHLC data from an on-disk HDF5 file. Minimising the amount of reads necessary, by reusing fixtures, resulted in a significant time saving.
It’s a pretty simple one, but an example of this can be found in my GitHub repo here.






