0

I'm trying to run the same test for a series of arguments using @pytest.mark.parametrize. The test data must be computed dynamically, which I attempted as follows:

data = [("1", "2")]

@pytest.fixture(scope="class")
def make_data():
    global data

    data.append(("3", "4"))

@pytest.mark.usefixtures("make_data")
class Tester:

    @pytest.mark.parametrize("arg0, arg1", data)
    def test_data(self, arg0, arg1):
        print(arg0, arg1)
        print(data)
        assert 0

I'm creating the data in the class scope fixture and then using it as the parameter set for test_data. I expect test_data to run twice, with arguments 1, 2 and 3, 4, respectively. However, what I get is a single test with arguments 1, 2 and the following stdout:

1 2
[('1', '2'), ('3', '4')]

The value of data is obviously [('1', '2'), ('3', '4')], which means that the class scoped fixture initialized it as I wanted. But somehow it appears that parametrization already happened before this.

Is there a cleaner way to achieve what I want? I could simply run a loop within the test_data method, but I feel like this defies the purpose of parametrization.

Is there a way to return data in the make_data fixture and use the fixture in @pytest.mark.parametrize? When using @pytest.mark.parametrize("arg0, arg1", make_data) I get TypeError: 'function' object is not iterable. make_data must be a fixture, because in the real test case it relies on other fixtures.

I am new to pytest and would be grateful for any hints. Thank you.

EDIT

To provide an explanation on why I'm doing what I'm doing: the way I understand, @pytest.mark.parametrize("arg0, arg1", data) allows parametrization with a hard-coded data set. What if my test data is not hard-coded? What if I need to pre-process it, like I tried in the make_data method? Specifically, what if I need to read it from a file or url? Let's say I have 1000 data samples for which to run the test case, how can I be expected to hard-code them?

Can I somehow use a function to generate the data argument in @pytest.mark.parametrize("arg0, arg1", data)? Something like:

def obtain_data():
    data = []
    # read 1000 samples
    # pre-process
    return data

@pytest.mark.parametrize("arg0, arg1", obtain_data())

This produces an error.

Gerry
  • 1,938
  • 3
  • 18
  • 25
  • 1
    This is not a great idea to introduce global variable in unittest. You should setup probably setup you test with "setup_method function" and clean it up with "teardown_method function". When there are more complex argument in test function (such as class with state) you should use a pytest.fixture. But never a global variable – PicxyB Nov 03 '22 at 10:54
  • 1
    There are several issues with this code, @PicxyB points one of them. Can you provide more information on what you are trying to achieve in this test? And expand what is the source of the data (for example can there be 2 functions where one generates `("1", "2")` and the other `("3", "4")`)? – Ilya Nov 03 '22 at 14:31

1 Answers1

0

As it turns out, the pytest-cases provides the option to define cases for the parametrization by functions, which helped a great deal. Hope this helps everyone who's looking for something similar

Gerry
  • 1,938
  • 3
  • 18
  • 25