SkylerHill-Sky
SkylerHill-Sky

Reputation: 2206

Parametrize class tests with pytest

I have an array of objects that I need to run for each test inside my test class. I want to parametrize every test function in a TestClass. The end goal is to have something resembling:

@pytest.mark.parametrize('test_input', [1, 2, 3, 4])
class TestClass:
    def test_something1(self, test_input):
        # test code here, runs each time for the parametrize

But from my understanding, you can't pass input parameters, or at least call @pytest.mark.parametrize on a class, those markers are meant for defs not classs

What I have now:

class TestClass:
    def test_something1(self):
        for i in stuff:
            # test code here

    def test_something2(self):
        for i in stuff:
            # test code here
    ...

Is there a way to pass the parametrize a class itself or every function inside the TestClass? Maybe a @pytest.mark.parametrize inside a @pytest.fixture...(autouse=True).

I want to keep my tests organized as a class because it mirrors the file that I'm testing. Because I loop through these objects in at least a dozen different tests, it would be easier to call a loop of the class than in each def.

Upvotes: 21

Views: 44255

Answers (2)

lmiguelvargasf
lmiguelvargasf

Reputation: 70003

You CAN apply parametrize to classes. From the docs:

@pytest.mark.parametrize allows one to define multiple sets of arguments and fixtures at the test function or class.

The same data will be sent to all test methods in the class.

@pytest.mark.parametrize('test_input', [1, 2, 3, 4])
class TestClass:
    def test_something1(self, test_input):
        pass


    def test_something2(self, test_input):
        pass

If you run the test with the following using pytest -v you will have the following output:

=========================================================================================== test session starts ============================================================================================
platform darwin -- Python 3.7.3, pytest-4.4.2, py-1.8.0, pluggy-0.11.0 -- /Users/user/.local/share/virtualenvs/stack-overlfow-pycharm-L-07rBZ9/bin/python3.7
cachedir: .pytest_cache
rootdir: /Users/user/Documents/spikes/stack-overlfow-pycharm
collected 8 items

test_class.py::TestClass::test_something1[1] PASSED                                                                                                                                                  [ 12%]
test_class.py::TestClass::test_something1[2] PASSED                                                                                                                                                  [ 25%]
test_class.py::TestClass::test_something1[3] PASSED                                                                                                                                                  [ 37%]
test_class.py::TestClass::test_something1[4] PASSED                                                                                                                                                  [ 50%]
test_class.py::TestClass::test_something2[1] PASSED                                                                                                                                                  [ 62%]
test_class.py::TestClass::test_something2[2] PASSED                                                                                                                                                  [ 75%]
test_class.py::TestClass::test_something2[3] PASSED                                                                                                                                                  [ 87%]
test_class.py::TestClass::test_something2[4] PASSED                                                                                                                                                  [100%]

========================================================================================= 8 passed in 0.03 seconds =========================================================================================

and this is exactly what you want.

Upvotes: 50

SkylerHill-Sky
SkylerHill-Sky

Reputation: 2206

I have solved it. I was overcomplicating it; instead of using a mark I can use a fixture function that passes in parameters.

Before I found the answer (Without parametrize):

class TestClass:
    def test_something(self):
        for i in example_params:
            print(i)

Answer, using pytest fixture. Will do the same thing, but just need input, not a for loop:

import pytest
example_params = [1, 2, 3]

@pytest.fixture(params=example_params)
def param_loop(request):
    return request.param

class TestClass:
    def test_something(self, param_loop):
        print(param_loop)

So, to parametrize all defs:

  1. Use the @pytest.fixture(params=[]) decorator on a def my_function(request)
  2. Inside my_function, return request.param
  3. Add the my_function to the inputs of any function that you want to parametrize

Upvotes: 8

Related Questions