Как разместить светильники PyTest и многострочные строки?

#python-3.x #pytest

Вопрос:

Я ищу способ более элегантно расположить светильники pytest.

Прямо сейчас мой тестовый каталог выглядит так:

 .
└── test
    └── cli
        ├── test_compile.py
        └── testdata
            └── ...
 

В test_compile у меня есть серия тестов, в каждом из которых в качестве входных данных используется приспособление (строка). Прямо сейчас я выкладываю все многострочные строки в нижней части файла. Итак, это выглядит так:

 def test_parse_zero_steps():
    _testStep(1, 1, py_zero_steps, "ZERO_STEPS")


py_zero_steps = """
# ---

foo = "bar"

#  
import tensorflow
"""
 

_testStep это внутренняя функция, которой я передаю ряд параметров, чтобы подтвердить, правильно ли я проанализировал большой двоичный объект.

Это уже довольно громоздко, и у меня есть более 20 строк, которые мне нужно использовать здесь для тестирования крайних случаев. Есть ли элегантный/более питонический способ сделать это? Я посмотрел на параметризацию (https://docs.pytest.org/en/6.2.x/example/parametrize.html) что выглядит намного приятнее, но все еще не ясно, что я должен делать с этими большими/раздражающими строками. Поместить их все в свои собственные отдельные файлы?

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

1. Есть ли какая-либо причина, по которой вы не смогли бы поместить многострочную строку в сам тестовый случай? например, например python def test_input_1(input): expected = ''' # --- foo = "bar" # import tensorflow ''' actual = some_py_call(input) assert actual == expected

2. о, конечно, но это затрудняет редактирование (при необходимости — маловероятно, но возможно) и делает серию тестов очень шумной для просмотра. Некоторые многострочные строки являются строками реального мира и могут быть довольно большими (~2000 символов и более).

Ответ №1:

Предполагая , что все ваши тесты будут просто вызываться _testSteps , лучший способ сделать это, вероятно, использовать parametrize , как уже упоминалось в вопросе. Тестовые данные могут быть в отдельном файле, либо в виде переменной или функции Python, либо в виде файла json (или в каком-либо другом формате), который может быть прочитан parametrize .

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

 def params():
    return [
        (
            1, 1, """
# ---

foo = "bar"

#  
import tensorflow
""",
            "ZERO_STEPS"
        ),
        (
            1, 2, """
# something sensible
""",
            "ONE_STEP"
        ),
...
    ]
 

Это может быть использовано в parametrize :

 @pytest.mark.parametrize("arg1, arg2, text, name", params(),
                         ids=[p[3] for p in params()])
def test_parse(arg1, arg2, text, name):
    _testStep(arg1, arg2, text, name)
 

Это выводит что-то вроде:

 $ pytest -vv
...
test_steps.py::test_parse[ZERO_STEPS] PASSED
test_steps.py::test_parse[ONE_STEP] PASSED
 

Обратите внимание, что я установил идентификаторы тестов name в качестве аргумента, чтобы избежать нечитаемых имен тестов. Это всего лишь пример, но имеет смысл адаптироваться ids из-за длинных строк. Без этого результат выглядел бы примерно так:

 test_steps.py::test_parse[1-1-n# ---nnfoo = "bar"nn#  nimport tensorflown-ZERO_STEPS] PASSED
test_steps.py::test_parse[1-2-n# something sensiblen-ONE_STEP] PASSED
 

что не совсем читаемо.