Using fixtures in pytest
Imagine multiple tests use the same data. In this case, both tests use the same list.
def test_sum():
assert sum([1, 2, 3, 3, 4, 5]) == 15
def test_length():
assert len([1, 2, 3, 3, 4, 5]) == 5
This results in duplicate code. If you have 10 functions, even more. If you want to change the data, you must modify it everywhere.
You can create a data
variable and use it in all tests. This solution is valid and may suffice in simple cases.
data = [1, 2, 3, 3, 4, 5]
def test_sum():
assert sum(data) == 15
def test_length():
assert len(data) == 5
However, pytest
offers fixture
for similar functionality with more control. The following code behaves the same, but you can pass the fixture
to each test individually.
import pytest
@pytest.fixture
def data():
return [1, 2, 3, 4, 5]
def test_sum(data):
assert sum(data) == 15
def test_length(data):
assert len(data) == 5
An interesting property is that pytest
maintains the fixture
value. If a test changes or deletes data
, nothing happens. Each test accesses a separate copy, unlike the previous method.
@pytest.fixture
def data():
return [1, 2, 3, 4, 5]
def test_sum(data):
assert sum(data) == 15
# We modify data here ...
data.append(6)
def test_length(data):
# ... but data does not change here
assert len(data) == 5
Returning to our ISS example, we can use the fixture
for the response
as follows.
@pytest.fixture
def response():
return {
'iss_position': {'latitude': 0, 'longitude': 0},
'message': 'success',
'timestamp': 1596563200
}
@pytest.fixture
def iss():
return DistanceISS(0, 0)
def test_coordinates_iss_non_numerics(response, iss):
with patch('iss.requests.get') as mock_get:
mock_get.return_value.json.return_value = response
mock_get.return_value.raise_for_status = lambda: None
assert iss.above() == True
Finally, you can configure the scope
of a fixture
as follows.
@pytest.fixture(scope="session")
def data():
return [1, 2, 3, 4, 5]
def test_sum(data):
assert sum(data) == 15
# We modify data here ...
data.append(6)
def test_length(data):
# ... and since it is a session fixture,
# it is modified here as well
assert len(data) == 5
The scope
determines when it is recreated. By default, function
is used, meaning each function receives a new fixture
.
Other options include session
, creating a single fixture
for the entire session. If modified in a test, it affects the rest.