Pytest class scope parametrization

Question:

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?

Asked By: vhdirk

||

Answers:

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()
Answered By: tmt

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.

Answered By: Ab Wilson
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.