Почему я получаю «Ошибку значения: дубликат» при передаче списка в «metafunc.parametrize` в» тестах pytest_generate_tests`

#python #pytest

Вопрос:

Я передаю файл json со следующим:

 #config.json
[
{
    "id" : 1,
    "description" : "test1",
    "data1": [1, 2, 3],
    "data2": ["foo", "bar", "baz"]
    
},
{
    "id" : 2,
    "description" : "test2",
    "data1": [4, 5, 6],
    "data2": ["baz", "foo"]
}
]
 

Попытка использовать data1 для создания тестовых перестановок. Самый элементарный способ вызвать проблему-это:

 #######################
# conftest.py
import json
import pathlib
import pytest

def pytest_generate_tests(metafunc):
    print("pytest_generate_tests")
    config = pathlib.Path(metafunc.module.__file__).with_name('config.json')
    testdata = json.loads(config.read_text())
    for test in testdata:
        metafunc.parametrize('testdata', testdata)
        metafunc.parametrize('data', test.get('data1'))

#######################

#test_example.py
import pytest

def test_example(testdata, data):
    pass
 

Что приводит к ошибке:

 external_data/conftest.py:11: in pytest_generate_tests
    metafunc.parametrize('data', test.get('data1'))
/usr/local/lib/python3.9/site-packages/pytest-6.2.3-py3.9.egg/_pytest/python.py:1100: in parametrize
    newcallspec.setmulti2(
/usr/local/lib/python3.9/site-packages/pytest-6.2.3-py3.9.egg/_pytest/python.py:932: in setmulti2
    self._checkargnotcontained(arg)
/usr/local/lib/python3.9/site-packages/pytest-6.2.3-py3.9.egg/_pytest/python.py:909: in _checkargnotcontained
    raise ValueError(f"duplicate {arg!r}")
E   ValueError: duplicate 'data'
 

Что я хотел бы видеть, так это то, что обе более широкие структуры будут проверены на все перестановки данных 1 (и, в конечном счете, данных 2)

 external_data/test_example.py::test_example[testdata0-1] PASSED
external_data/test_example.py::test_example[testdata0-2] PASSED
external_data/test_example.py::test_example[testdata0-3] PASSED
external_data/test_example.py::test_example[testdata1-4] PASSED
external_data/test_example.py::test_example[testdata1-5] PASSED
external_data/test_example.py::test_example[testdata1-6] PASSED
 

Ответ №1:

Вы должны передать список для параметризации, иначе вы просто вызываете parametrize('data',...) несколько раз с разными аргументами.

Что — то вроде этого должно сработать:

 def pytest_generate_tests(metafunc):
    print("pytest_generate_tests")
    config = pathlib.Path(metafunc.module.__file__).with_name('config.json')
    testdata = json.loads(config.read_text())
    data = [test.get('data') for test in testdata]
    metafunc.parametrize('data', data)
 

параметризация принимает итерацию в качестве второго аргумента.

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

1. данные становятся списком списков [[1,2,3],[4,5,6]]. test.get('data1') возвращает повторяющийся список.