I have tests that are identical for various values, so I want to parametrize the test class. Because the code is making network calls, I also want to use class scoped fixtures.
I tried
import pytest
@pytest.mark.parametrize('fruit', ['apple', 'banana'])
class TestFruit:
@pytest.fixture(scope='class')
def get_fruit(self, fruit):
print(f'Network call to GET {fruit}. This is expensive.')
return fruit
def test_fruit(self, get_fruit):
print(f'The fruit is {get_fruit}.')
assert get_fruit == 'apple'
def test_fruit2(self, get_fruit):
print(f'Fruit in test_fruit2 is {get_fruit}')
assert get_fruit == 'orange'
I want all of the tests to be run for every 'fruit' listed, and I want get_fruit
to only be called once per class, not for each test.
When I run the code, I get ScopeMismatch: You tried to access the function scoped fixture endpoint with a class scoped request object
Unexpected behavior of class scoped fixture when calling a class scoped parametrized fixture in Pytest describes the issue I'm having, but I don't see a difference between the code posted in the question and the code posted in the answer.
One possible fix is to make the scope of get_fruit
function instead of class, but I don't think you want to do this because the network call is expensive.
Another solution is to combine the fixture and the parameterize into one:
import pytest
@pytest.fixture(
scope="class",
params=["apple", "banana"],
)
def get_fruit(request):
fruit = request.param
print(f"Network call to GET {fruit}. This is expensive.")
return fruit
class TestFruit:
def test_fruit(self, get_fruit):
print(f"The fruit is {get_fruit}.")
assert get_fruit == "apple"
def test_fruit2(self, get_fruit):
print(f"Fruit in test_fruit2 is {get_fruit}")
assert get_fruit == "orange"
This way, the fixture is called only once per fruit, per class.
If you run your tests, you will have a total of 4 tests (2 tests x 2 parameters). However, there are only 2 network calls, one for each fruit.