Let's say I have a simple fixture like the following (using pytest-django, but it applies to pytest as well):
@pytest.fixture def my_thing(request, db): thing = MyModel.objects.create() request.addfinalizer(lambda: thing.delete()) return thing
This works great when my tests need a single instance of MyModel. But what about if I need two (or three or four)? I want each instance to be distinct, but to be set up in the same way.
I could copy/paste the code and rename the fixture function, but that seems inelegant.
Similarly, I have tried:
@pytest.fixture def my_thing_1(my_thing): return my_thing @pytest.fixture def my_thing_2(my_thing): return my_thing
However, each of these appears to return the same instance of MyModel.
Is there a way to do what I want using pytest's built-in functionality? Alternately, I could move the setup/teardown of my fixture out into helper functions so I'm not duplicating too much code.
Or am I going about this whole thing the wrong way?
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.
Module: If the Module scope is defined, the fixture will be created/invoked only once per module. Class: With Class scope, one fixture will be created per class object. Session: With the Session scope, the fixture will be created only once for entire test session.
Fixtures can also be requested more than once during the same test, and pytest won't execute them again for that test. This means we can request fixtures in multiple fixtures that are dependent on them (and even again in the test itself) without those fixtures being executed more than once.
Fixtures with scope session will only be executed once per session. Every time you run pytest , it's considered to be one session.
My approach would probably to create a fixture which can generate your objects:
@pytest.fixture def thing(request, db): class ThingFactory(object): def get(self): thing = MyModel.objects.create() request.addfinalizer(thing.delete) return thing return ThingFactory() def test_thing(thing): thing1 = thing.get() thing2 = thing.get()
Obviously you can make .get()
take an argument etc.
(PS: Also note there's no need for the lambda in the finalizer)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With