Using pytest to test different instances of the same class

Viewed 1442

What I want to do

I want to use pytest (Python 3.x) to run a set of unittests on different instances of the same class.

The idea which I try to implement

I want to iterate through a predefined list of parameters. For example, I select the first entry of that list and instantiate my class with the respective parameters. Then, I run all tests where all tests operate on the same instance of my class. If the tests were completed successfully, we pick the second entry of our parameter list, re-instantiate my class, and run the tests again. We repeat this process until we reached the end of the parameter list or a test fails.

What I have tried so far

So far, thinks are working expect for the "iterating through a predefined list of parameters" part. In particular, I created a class with the following structure:

@pytest.mark.usefixtures('setup_func')
class TestA(unittest.TestCase):
    def test_1(self):        
        # do something with self.my_obj
        self.assertEqual(X, Y)
        
    def test_2(self):
        # do something with self.my_obj
        self.assertEqual(V, W)

As you can see, I definied a usefixtures at the top; hence, when I execute the command pytest tests, first the respective function is called (where I instantiate my_obj), and then the tests are executed. setup_func is stored in conftest.py and looks as follows:

@pytest.fixture(scope='class')
def setup_func(request):
    my_obj = ...  # create the object
    request.cls.my_obj = my_obj

I am not sure if this is clear, but modifications in test_1() on self.my_obj are visible in test_2() -and this is intended. The tests essentially execute a process step-by-step within my_obj and test after each step if things are as expected.

My Question

How do I have to modify my example above to repeat the whole procedure with different instances of my_obj?

Disclaimer: I know that there are already a lot of discussions/posts/etc. an people usually refer to @pytest.mark.parametrize; however, I don't see how this would be applicable here.

Restriction

I see that it would be possible to pre-instantiate all possible my_obj instances already in setup_func and then just pass a list of these objects to the test functions. However, this is not feasible in my scenario as a single my_obj already needs a lot of memory (as it is a data generator).

1 Answers

You could use pytest parametrizing fixtures. Below is pure pytest example without mixing with Unittest. Maybe this will help a little

import pytest


class MyObj:
    def __init__(self, val):
        self.val = val
        self.step = 0

    def __str__(self):
        return f"MyObj val:{self.val} step: {self.step}"


@pytest.fixture(scope='class', params=["1", "2"])
def my_obj(request):
    my_obj = MyObj(request.param)
    return my_obj


@pytest.mark.usefixtures("my_obj")
class TestA:
    def test_1(self, my_obj):
        my_obj.step = 1
        print(my_obj)
        pass

    def test_2(self, my_obj):
        my_obj.step = 2
        print(my_obj)

Output:

MyObj val:1 step: 1
MyObj val:1 step: 2
MyObj val:2 step: 1
MyObj val:2 step: 2

Related