Multiple copies of a pytest fixture
Question:
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?
Answers:
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)
I’m arriving at this question very late… but, using a parametrized fixture and simply returning the fixture you want to duplicate seems to work too.
import pytest
import random
@pytest.fixture
def name():
return random.randint(0, 10)
@pytest.fixture(params=[0, 1])
def parametrized_name(request, name):
return name
def test_something(parametrized_name):
print "Testing with name: " + str(parametrized_name)
If you run the above test, you get 2 different “name” fixtures
$ pytest -s blah.py
============================================= test session starts ==============================================
platform linux2 -- Python 2.7.14, pytest-3.3.2, py-1.5.2, pluggy-0.6.0
rootdir: /home/bsquizza/repos/blah/tests, inifile:
collected 2 items
blah.py Testing with name: 7
.Testing with name: 10
. [100%]
=========================================== 2 passed in 0.01 seconds ===========================================
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?
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)
I’m arriving at this question very late… but, using a parametrized fixture and simply returning the fixture you want to duplicate seems to work too.
import pytest
import random
@pytest.fixture
def name():
return random.randint(0, 10)
@pytest.fixture(params=[0, 1])
def parametrized_name(request, name):
return name
def test_something(parametrized_name):
print "Testing with name: " + str(parametrized_name)
If you run the above test, you get 2 different “name” fixtures
$ pytest -s blah.py
============================================= test session starts ==============================================
platform linux2 -- Python 2.7.14, pytest-3.3.2, py-1.5.2, pluggy-0.6.0
rootdir: /home/bsquizza/repos/blah/tests, inifile:
collected 2 items
blah.py Testing with name: 7
.Testing with name: 10
. [100%]
=========================================== 2 passed in 0.01 seconds ===========================================