Reputation: 598
I have a couple of fixtures that do some initialization that is rather expensive. Some of those fixtures can take parameters, altering their behaviour slightly.
Because these are so expensive, I wanted to do initialisation of them once per test class. However, it does not destroy and reinit the fixtures on the next permutation of parameters.
See this example: https://gist.github.com/vhdirk/3d7bd632c8433eaaa481555a149168c2
I would expect that StuffStub
would be a different instance when DBStub
is recreated for parameters 'foo' and 'bar'.
Did I misunderstand something? Is this a bug?
Upvotes: 0
Views: 751
Reputation: 335
I've recently encountered the same problem and wanted to share another solution. In my case the graph of fixtures that required regenerating for each parameter set was very deep and it's not so easy to control. An alternative is to bypass the pytest parametrization system and programmatically generate the test classes like so:
import pytest
import random
def make_test_class(name):
class TestFoo:
@pytest.fixture(scope="class")
def random_int(self):
return random.randint(1, 100)
def test_someting(self, random_int):
assert random_int and name == "foo"
return TestFoo
TestFooGood = make_test_class("foo")
TestFooBad = make_test_class("bar")
TestFooBad2 = make_test_class("wibble")
You can see from this that three tests are run, one passes (where "foo" == "foo") the other two fail, but you can see that the class scope fixtures have been recreated.
Upvotes: 0
Reputation: 8604
This is not a bug. There is no relation between the fixtures so one of them is not going to get called again just because the other one was due to having multiple params
.
In your case db
is called twice because db_factory
that it uses has 2 params
. The stuff
fixture on the other hand is called only once because stuff_factory
has only one item in params
.
You should get what you expect if stuff
would include db_factory
as well without actually using its output (db_factory
would not be called more than twice):
@pytest.fixture(scope="class")
def stuff(stuff_factory, db_factory):
return stuff_factory()
Upvotes: 0