9

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.

lmiguelvargasf
  • 51,786
  • 40
  • 198
  • 203
Comradsky
  • 1,996
  • 2
  • 16
  • 32

2 Answers2

27

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.

lmiguelvargasf
  • 51,786
  • 40
  • 198
  • 203
  • Using this syntax, is it possible to parametrize the setup_method(), too? It seems that parameters don't apply to setup_method. Possibly, it searches for methods with a test_ prefix. – Thanasis Mattas Oct 14 '20 at 10:04
  • 2
    This unfortunately does not work if your test classes inherits from `unittest.TestCase`, which might be needed in some cases. – spookylukey May 24 '21 at 09:04
  • I was looking to this solution, but here each test func. runs for provided input param then execution goes to other test function. Is is posible the for 1s iteration, all func. of the class runs and then 2nd iteration starts, something like: test_something1[1] test_something2[1] test_something1[2] test_something2[2] – Dcode Oct 23 '21 at 10:14
2

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
Comradsky
  • 1,996
  • 2
  • 16
  • 32
  • I stumbled upon your comment, as I was looking exactly for this, however, if I try to implement the test the way you explained it I get the error: `Failed: Database access not allowed, use the "django_db" mark, or the "db" or "transactional_db" fixtures to enable it.` and if I put `example_params` in the class I get pass the error, but then I get the error that `param_loop` is missing. Have you had the same issues? @Comradsky – filtfilt Apr 17 '17 at 20:29
  • See also [here](https://stackoverflow.com/questions/17434031/py-test-parametrizing-test-classes/22417893#22417893) and [here](https://docs.pytest.org/en/latest/fixture.html#fixture-parametrize) – Christian Long Jul 05 '18 at 16:39
  • It's possible to use `parametrize` function with specific method of your `class TestMyCustomTestCase`and avoid this workaround. – cpinamtz Jan 08 '20 at 08:50