1

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.

1 Answers1

0

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.

Hai Vu
  • 37,849
  • 11
  • 66
  • 93
  • Thank you! I didn't know that a `fixture` can be parametrized, which may be a more elegant solution than the one I "finally* came up with. You nailed it - my issue was that I was trying to pass items from `fruit` into `get_fruit()`, but what worked was passing in the `request` and returning `request.param`. I really appreciate your help! – Davina Armstrong May 16 '23 at 14:21