parameterized test with cartesian product of arguments in pytest

You can apply multiple parametrize arguments, in which case they will generate a product of all parameters:

import pytest

numbers = [1,2,3,4,5]
vowels = ['a','e','i','o','u']
consonants = ['x','y','z']


@pytest.mark.parametrize('number', numbers)
@pytest.mark.parametrize('vowel', vowels)
@pytest.mark.parametrize('consonant', consonants)
def test(number, vowel, consonant):
    pass

I can think of two ways to do this. One uses parametrized fixtures, and one parametrizes the test function. It's up to you which one you find more elegant.

Here is the test function parametrized:

import itertools
import pytest

numbers = [1,2,3,4,5]
vowels = ['a','e','i','o','u']
consonants = ['x','y','z']


@pytest.mark.parametrize('number,vowel,consonant',
    itertools.product(numbers, vowels, consonants)
)
def test(number, vowel, consonant):
    pass

Of note, the second argument to the parametrize decorator can be an iterable, not just a list.

Here is how you do it by parametrizing each fixture:

import pytest

numbers = [1,2,3,4,5]
vowels = ['a','e','i','o','u']
consonants = ['x','y','z']


@pytest.fixture(params=numbers)
def number(request):
    return request.param

@pytest.fixture(params=vowels)
def vowel(request):
    return request.param

@pytest.fixture(params=consonants)
def consonant(request):
    return request.param


def test(number, vowel, consonant):
    pass

Your intuition was correct. By parametrizing each of multiple fixtures, pytest takes care of creating all the permutations that arise.

The test output is identical. Here is a sample (I ran py.test with the -vv option):

test_bar.py:22: test[1-a-x] PASSED
test_bar.py:22: test[1-a-y] PASSED
test_bar.py:22: test[1-a-z] PASSED
test_bar.py:22: test[1-e-x] PASSED
test_bar.py:22: test[1-e-y] PASSED
test_bar.py:22: test[1-e-z] PASSED
test_bar.py:22: test[1-i-x] PASSED

Tags:

Python

Pytest