5

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
  • This is an excellent question. Thank you for taking the time to read how to ask a question! Commented Oct 25, 2020 at 0:37

1 Answer 1

3

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

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! That works but I want to highlight that this is not compatible with Unittests. Things crash with a pretty clear warning message. However, this is at least in my scenario not a problem -I just replaced the Unittests.assertEqual methods.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.