Один тест, много случаев
Большинству функций нужна одна и та же проверка для многих входных данных: обычные значения, отрицательные значения, ноль, граничные случаи. Если скопировать тест пять раз, придётся поддерживать пять мест.
Решение — табличный тест: поместите случаи в список кортежей — каждый случай содержит название, входные данные и ожидаемый результат — и выполните одну и ту же проверку для всех них.
Добавление нового случая превращается в одну новую строку в таблице. Это один из самых распространённых шаблонов тестов, который вы встретите в реальном коде.
Таблица
Самая простая таблица — это список кортежей прямо внутри теста. Каждая запись — один случай: название (для сообщения об ошибке), входные данные и ожидаемый результат.
Цикл вызывает функцию один раз для каждого случая и сравнивает результат. Первое несовпадение остановило бы тест на этом случае, а сообщение содержит название случая — так вы узнаёте, какая строка сломалась.
Четыре случая в одной таблице
Четыре случая, один цикл, одна проверка. Здесь все проходят, поэтому запуск показывает один пройденный тест. Чтобы проверить пятую ситуацию, достаточно добавить одну строку в таблицу — цикл остаётся без изменений.
Вывод: полная программа на Python
def add(a, b):
return a + b
def test_add():
cases = [
("один плюс один", 1, 1, 2),
("положительное и отрицательное", 5, -3, 2),
("оба отрицательные", -2, -4, -6),
("нули", 0, 0, 0),
]
for name, a, b, want in cases:
got = add(a, b)
assert got == want, f"{name}: add({a}, {b}) = {got}; ожидалось {want}"
Отдельный тест для каждого случая с parametrize
pytest может превратить каждую строку таблицы в отдельный тест: декоратор @pytest.mark.parametrize принимает имена аргументов и список случаев и вызывает тестовую функцию один раз для каждой строки.
Список ids даёт каждому случаю имя. Теперь имена появляются в выводе pytest -v, например test_add[both_negative]. Каждый случай проходит или падает сам по себе, поэтому сломанную строку легко заметить в длинной таблице — а строки после неё всё равно проверяются.
Каждый случай получает имя
Та же таблица, записанная в виде случаев parametrize. Подробный вывод теперь перечисляет все четыре случая отдельно — видно, какие именно случаи выполнились и прошли, а итог сообщает 4 passed.
Вывод: полная программа на Python
import pytest
def add(a, b):
return a + b
@pytest.mark.parametrize("a, b, want", [
(1, 1, 2),
(5, -3, 2),
(-2, -4, -6),
(0, 0, 0),
], ids=["one_plus_one", "positive_and_negative", "both_negative", "zeros"])
def test_add(a, b, want):
assert add(a, b) == want
Запуск одного случая
Случаи можно выбирать из командной строки с помощью -k, который сопоставляется с именем теста и id случая:
pytest -v -k "both_negative"
Выполняется только подходящий случай; остальные исключаются (deselected) и даже не запускаются. Это идеально подходит, когда вы исправляете один сломанный случай: перезапускайте только его, пока он не станет зелёным, а затем снова запустите всё.
Фильтрация с -k
Тот же файл, что и выше, запущенный с -k "both_negative". Выполняется только один из четырёх случаев — в заголовке указано 3 deselected и 1 selected, а итог сообщает 1 passed, 3 deselected.
Вывод: полная программа на Python
import pytest
def add(a, b):
return a + b
@pytest.mark.parametrize("a, b, want", [
(1, 1, 2),
(5, -3, 2),
(-2, -4, -6),
(0, 0, 0),
], ids=["one_plus_one", "positive_and_negative", "both_negative", "zeros"])
def test_add(a, b, want):
assert add(a, b) == want