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.