Hi, I would like to ask if there is a best practice to parametrize a fixture in the sense of passing a parameter to it.
The first thing that comes to my mind is that it might not be a good idea at all, maybe fixtures should have no parameters so that they can really be pre-initialized objects that are used as starting points for tests.
But let’s discuss an example I’m facing in a real application:
I would like to create a fixture structure for this object hierarchy: Design -> Site -> Node, meaning that a design can contain sites, and a site can contain nodes.
So this is my fixture structure:
@pytest.fixture def design(): ... @pytest.fixture def site(design): ... @pytest.fixture def node(site): ...
So I can easily write tests starting from any of these elements and have the “parent” elements managed for free.
The problem: I can have two different kinds of “design” that are created with different parameters while the child objects remain the same. So I would like to be able, in some way, to say: use the designTypeA fixture or designTypeB fixture but also: use the node fixture with a designTypeA o designTypeB parent.
The solutions I found (and why I don’t love them):
One possibility is to duplicate the whole fixture structure and have a
designTypeA->siteTypeA->nodeTypeA and a designTypeB->siteTypeB->nodeTypeB
This is so redundant if the hierarchy is big enough
A second possibility is to use “indirect=True” https://stackoverflow.com/a/33879151/1534775 but I dislike the fact that you have to use the @pytest.mark.parametrize decorator with all that parameters, it’s unreadable and doesn’t look like a fixture
The third option is to use introspection to access the request object and leave some sort of flag in the calling test and act accordingly when creating the fixture.
it’s the option I’ve chosen so far but it feels like a hack
My solution is even more hacked together than a simple flag, I’m basically using the mark decorator (the label) as a flag.
@pytest.fixture def design(request): if request.keywords._marker.get('TypeA'): _create_typeA() else: .... @pytest.fixture def site(design): ... @pytest.fixture def node(site): ...
and in the test
@pytest.mark.TypeA def test_something(design): pass
I’d love to hear some else’s opinion on what approach you suggest, if it’s a terrible idea :) or even if it make sense at all.