Closed mtraynham closed 2 years ago
To give an idea of how this was before adopting lazy_fixture, we only had one level of parameterization, but this required multiple tests.
import pytest
@pytest.fixture(scope='session')
def location_a() -> str:
return 'location_a'
@pytest.fixture(scope='session')
def location_b() -> str:
return 'location_b'
@pytest.fixture(params=[
'location_a',
'location_b'
], scope='session')
def primary_location(request: pytest.FixtureRequest) -> str:
return request.getfixturevalue(request.param)
@pytest.fixture(scope='session')
def location_c() -> str:
return 'location_c'
@pytest.fixture(scope='session')
def location_d() -> str:
return 'location_d'
@pytest.fixture(params=[
'location_c',
'location_d'
], scope='session')
def secondary_location(request: pytest.FixtureRequest) -> str:
return request.getfixturevalue(request.param)
@pytest.fixture(scope='session')
def cloud_port_c() -> str:
return 'cloud_port_c'
@pytest.fixture(scope='session')
def cloud_port_d() -> str:
return 'cloud_port_d'
@pytest.fixture(params=[
'cloud_port_c',
'cloud_port_d'
], scope='session')
def cloud_port(request: pytest.FixtureRequest) -> str:
return request.getfixturevalue(request.param)
@pytest.fixture(scope='session')
def port(primary_location: str) -> str:
return f'port-{primary_location}'
@pytest.fixture(scope='session')
def port_group(primary_location: str) -> str:
return f'port_group-{primary_location}'
@pytest.fixture(scope='session')
def secondary_port(secondary_location: str) -> str:
return f'secondary_port-{secondary_location}'
@pytest.fixture(scope='session')
def port_attachment(secondary_port: str) -> str:
return f'port_attachment-{secondary_port}'
@pytest.fixture(scope='session')
def cloud_attachment(cloud_port: str) -> str:
return f'cloud_attachment-{cloud_port}'
def test_port_to_port_attachment(port: str, port_attachment: str) -> None:
print(f'{port}-{port_attachment}')
def test_port_to_cloud_attachment(port: str, cloud_attachment: str) -> None:
print(f'{port}-{cloud_attachment}')
def test_port_group_to_port_attachment(port_group: str, port_attachment: str) -> None:
print(f'{port_group}-{port_attachment}')
def test_port_group_to_cloud_attachment(port_group: str, cloud_attachment: str) -> None:
print(f'{port_group}-{cloud_attachment}')
After looking at the pytest documentation, maybe this is expected. Kind of unfortunate, some of my fixtures are a bit expensive to create and teardown.
Pytest only caches one instance of a fixture at a time, which means that when using a parametrized fixture, pytest may invoke a fixture more than once in the given scope.
https://docs.pytest.org/en/6.2.x/fixture.html#fixture-scopes
Hi, I have a fairly complex set of fixtures to help with parameterization of polymorphic requests. Unfortunately it seems that some of the fixtures stop respecting their intended scope and are called multiple times.
Theoretically, let's say we are building a graph which has vertices & edges. Well, the vertices themselves can be polymorphic fixtures, some of their properties can be mutated, and the test cases are building edges between them.
In the following example, I have a series of network primitives, Ports & Cloud Ports, which may have multiple locations associated with them. At the end, I take two vertex fixtures and test them.
The test list looks fine, but the count of how many times a session scoped fixture is invoked seems incorrect. In all cases, I would have expected the counts to match how many dependent parameters there are, but in some cases I see 8, others I see 16. I use a wrapper here to collect invocation counts and dump them at the end of the tests.
It's as if the cache key is invalidated or doesn't match because of where the fixture is referenced in the hierarchy of fixtures.