маркировка теста как xfail с двойной параметризацией в pytest

#pytest #parametrized-testing

#python #pytest #параметризованный-тестирование

Вопрос:

У меня есть тест pytest, который проверяет несколько входных данных для двух разных баз данных. я делаю это, используя параметризованную метку дважды:

 @pytest.mark.parametrize(
    "input_type",
    [
        pytest.param("input_1"),
        pytest.param("input_2"),
    ],
)
@pytest.mark.parametrize(
    "db_type",
    [
        pytest.param("db_type_1"),
        pytest.param("db_type_2"),
    ],
)
  

То, что я испытываю, происходит только при запуске input_1 db_type_2 (например), когда тест завершается неудачей из-за ошибки
, но выполняется один и тот же ввод с разными проходами БД.
Я хочу пометить только input_1 db_type_2 комбинацию and как xfail, в то время как все остальные комбинации не должны быть помечены как xfail.
Я не могу найти, как это сделать.

Если маркировка db_type_2 как xfail:

 @pytest.mark.parametrize(
    "db_type",
    [
        pytest.param("db_type_1"),
        pytest.param("db_type_2", marks=pytest.mark.xfail)
    ],
)
  

все входные данные будут xfailed, и это не то поведение, которое я ищу.
Может ли кто-нибудь помочь мне с этим?

Комментарии:

1. Если вы все еще рядом, теперь вы можете принять один из ответов.

Ответ №1:

Вы не можете пометить тест на основе полного набора аргументов в pytest.mark.parametrize / pytest.param , информации о других аргументах просто еще нет. Обычно я переношу постобработку параметров теста в отдельный инструмент, который затем может изменять тест на основе полного набора тестовых аргументов. Пример:

 @pytest.mark.parametrize('x', range(10))
@pytest.mark.parametrize('y', range(20))
def test_spam(x, y):
    assert False
  

Всего у нас 200 тестов; предположим, мы хотим xfail протестировать для x=3 , y=15 и x=8 , y=1 . Мы добавляем новое приспособление xfail_selected_spams , которое получает доступ к обоим x и y перед test_spam запуском и xfail при необходимости добавляет маркер в тестовый экземпляр:

 @pytest.fixture
def xfail_selected_spams(request):
    x = request.getfixturevalue('x')
    y = request.getfixturevalue('y')

    allowed_failures = [
        (3, 15), (8, 1),
    ]
    if (x, y) in allowed_failures:
        request.node.add_marker(pytest.mark.xfail(reason='TODO'))
  

Чтобы зарегистрировать приспособление, используйте pytest.mark.usefixtures :

 @pytest.mark.parametrize('x', range(10))
@pytest.mark.parametrize('y', range(20))
@pytest.mark.usefixtures('xfail_selected_spams')
def test_spam(x, y):
    assert False
  

При запуске тестов сейчас мы получим 198 failed, 2 xfailed результаты, поскольку ожидается, что два выбранных теста завершатся неудачей.

Ответ №2:

Вы могли бы создать функцию, которая будет выполняться во время сбора тестов и обрабатывает параметризацию и xfail метку на основе данных

 def data_source():
    input_types = ['input_1', 'input_2']
    db_types = ['db_type_1', 'db_type_2']

    for tup in itertools.product(input_types, db_types):
        marks = []
        if tup == ('input_1', 'db_type_2'):
            marks.append(pytest.mark.xfail(reason=f'{tup}'))
        yield pytest.param(tup, marks=marks)

@pytest.mark.parametrize('test_data', data_source())
def test_example(self, test_data):
    assert test_data != ('input_1', 'db_type_2')
  

itertools.product позволяет добавить еще один список входных данных без изменения какой-либо другой части кода, за исключением if условия для разрешенных входных данных.

Комментарии:

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