python - pytest: параметризованный тест с декартовым произведением аргументов




unit-testing (2)

Вы можете применить несколько аргументов parametrize , в этом случае они будут генерировать произведение всех параметров:

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

Просто интересно, есть ли (более) элегантный способ параметризации с помощью декартового произведения? Это то, что я понял до сих пор:

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

cartesian = [elem for elem in itertools.product(*[numbers,vowels,consonants])]

@pytest.fixture(params=cartesian)
def someparams(request):
  return request.param

def test_something(someparams):
  pass

По крайней мере, я хотел бы заключить числа, гласные, согласные и декартовы в функцию фикстуры.


Я могу придумать два способа сделать это. Один использует параметризованные приборы, а другой параметризует тестовую функцию. Вам решать, какой из них вы найдете более элегантным.

Вот параметризованная тестовая функция:

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

Следует отметить, что второй аргумент декоратора параметризации может быть итеративным, а не просто списком.

Вот как вы делаете это путем параметризации каждого прибора:

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

Ваша интуиция была правильной. Путем параметризации каждого из нескольких приборов pytest заботится о создании всех перестановок, которые возникают.

Результаты теста идентичны. Вот пример (я запустил py.test с опцией -vv):

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




pytest