11

I am using pytest's parametrize annotations to pass params into a class. I'm able to use the parameters in the test methods, however, I can't figure out how to use the parameters in the setup_class method.

import pytest

params = ['A','B','C']

@pytest.mark.parametrize('n', params)
class TestFoo:

    def setup_class(cls):
        print ("setup class:TestFoo")
        # Do some setup based on param

    def test_something(self, n):
        assert n != 'D'

    def test_something_else(self, n):
        assert n != 'D'

I tried adding 'n' as a parameter like the test methods, like this:

def setup_class(cls, n):
        print ("setup class:TestFoo")
       # Do some setup based on param

Which results in an error:

self = <Class 'TestFoo'>

    def setup(self):
        setup_class = xunitsetup(self.obj, 'setup_class')
        if setup_class is not None:
            setup_class = getattr(setup_class, 'im_func', setup_class)
            setup_class = getattr(setup_class, '__func__', setup_class)
>           setup_class(self.obj)
E           TypeError: setup_class() takes exactly 2 arguments (1 given)

Is there some other way of using the parameter in the setup_class method?

user2945303
  • 111
  • 1
  • 1
  • 4

2 Answers2

7

You can't.

First, setup_class is called only once per class, even if there is parametrize fixture used - class is set up only once.

Second, it is not designed to take any other params than cls. It will not accept params from paramterize and other fixtures.

As a solution, you could use a parametrized fixture with "class" scope:

import pytest

params = ['A', 'B', 'C']


@pytest.fixture(
    scope="class",
    params=params,
)
def n(request):
    print('setup once per each param', request.param)
    return request.param


class TestFoo:

    def test_something(self, n):
        assert n != 'D'

    def test_something_else(self, n):
        assert n != 'D'

For more info look at http://docs.pytest.org/en/latest/fixture.html#fixture-parametrize

prmtl
  • 421
  • 5
  • 10
  • It's even nicer to use `autouse=True` in the fixture. With that, the test methods do not have to request the fixture explicitly. See also https://stackoverflow.com/questions/61305801/pytest-how-to-include-setup-fixture-with-scope-class – Domi W Feb 10 '23 at 21:02
-4

You should pass attributes to your test class by assigning it to cls. All attributes and functions that you assign to it later will become class attrubutes / methods.

Parametrized decorator should be used on class methods (you want to test methods, don't you?)

So:

import pytest

params = ['A','B','C']

class TestFoo:

    def setup_class(cls):
        cls.n = params

    @pytest.mark.parametrize('n', params)
    def test_something(self, n):
        assert n != 'D'

    @pytest.mark.parametrize('n', params)
    def test_something_else(self, n):
        assert n != 'D'

    def test_internal(self):
        assert self.n != params

Test will fail on test_internal. It illustrates thatparamswere set toself.nand nowself.nequals toparams`

nickzam
  • 793
  • 4
  • 8
  • 2
    This doesn't really solve what I'm trying to do. In each test, 'n' is an item from the params list. In your example, you're assigning the entire list to cls.n. By doing it at the class level, what I want is, for item 'A', run setup specific to item 'A', then run tests for item 'A'. – user2945303 Nov 04 '13 at 16:55
  • In addition, what is this? For instance, it does not even use the decorator for the setup method in the class, does not have corresponding tear down, and so on. – László Papp Sep 02 '14 at 13:33