Программирование17 октября 2026 г.

Как проверить несколько входных случаев одним параметризованным тестом pytest

Автор
Ненашев А.
На чтение
6 мин
Дата обновления
17.10.2026
Старт:В любой момент
Срок обучения:4 месяца
Комплект курсов «Автоматизация тестов на Python» и «Python программист»
«Автоматизированное тестирование на Python»: Стань автоматизатором на Python. Практические задания с unittest и pytest помогут закрепить знания и начать автоматизировать реальные кейсы.«Python программист с нуля»: Нельзя стать автоматизатором на Python, не зная Python. Освой один из самых популярных языков с нуля: научишься работать с переменными, условиями, циклами и функциями. Поймёшь основы ООП, файлового ввода-вывода и начнёшь автоматизировать простые задачи. Идеально для тех, кто хочет в автоматизацию.
Подробнее
31 290 ₽34 775 ₽
#COURSE##INNER#

Как проверить несколько входных случаев одним параметризованным тестом pytest

Когда один параметризованный тест лучше набора почти одинаковых проверок

Если вы проверяете чистую функцию, то сама форма теста обычно не меняется: подали вход, получили результат, сравнили с ожидаемым. Меняются только числа. Из-за этого шесть отдельных тестов вроде test_shipping_0, test_shipping_999 и test_shipping_1000 быстро превращаются в копии друг друга. Читать их неудобно: правило размазано по файлу, а повторяющийся код скрывает границы, где чаще всего и живет ошибка.

Параметризация полезна именно в таких задачах. Она позволяет вынести правило в таблицу: вот вход, вот ожидаемый результат, вот одна и та же проверка, которая выполняется для каждого случая. Для функции стоимости доставки это особенно наглядно, потому что логика строится на порогах. Если разработчик случайно напишет > вместо >=, обычные суммы могут пройти, а значения ровно на пороге — нет. Один параметризованный тест собирает эти точки в одном месте и делает ошибку заметной.

Таблица входов и ожидаемых результатов

Начать лучше не с декоратора, а с маленькой таблицы. Она дисциплинирует: вы сначала формулируете правило в числах, а потом уже переносите его в код. Возьмем полностью условную учебную модель, без связи с реальными тарифами: если сумма заказа меньше 1000, доставка стоит 300; если сумма от 1000 до 2999, доставка стоит 150; если сумма от 3000, доставка бесплатна.

Учебный пример. Наша цель — не перебрать все суммы подряд, а выбрать контрольные точки, которые проверяют арифметику на границах. Для этого достаточно начала шкалы, значений прямо перед порогами и самих порогов.

Сумма заказаОжидаемая стоимость доставкиЗачем этот случай нужен
0300Нижняя граница допустимых значений
999300Число прямо перед первым порогом
1000150Первый порог, где цена должна измениться
2999150Число прямо перед бесплатной доставкой
30000Порог бесплатной доставки
45000Обычное значение внутри верхнего диапазона

Такая таблица полезнее длинного списка случайных чисел. Она проверяет именно переходы между зонами. Если функция ошибается на 1000 или 3000, вы сразу видите, что сломано правило сравнения, а не вся логика целиком.

Как превратить таблицу в один тест

Теперь таблицу можно перенести в pytest.mark.parametrize. Ниже пример для среды Python 3 и pytest. Функция специально сделана чистой: она зависит только от входного числа и ничего не читает извне. Это упрощает проверку, потому что каждое выполнение теста изолировано по смыслу.

# shipping.py
def shipping_cost(order_total: int) -> int:
    if order_total < 0:
        raise ValueError("order_total must be non-negative")
    if order_total >= 3000:
        return 0
    if order_total >= 1000:
        return 150
    return 300

# test_shipping.py
import pytest
from shipping import shipping_cost

@pytest.mark.parametrize(
    "order_total, expected",
    [
        (0, 300),
        (999, 300),
        (1000, 150),
        (2999, 150),
        (3000, 0),
        (4500, 0),
    ],
)
def test_shipping_cost(order_total, expected):
    assert shipping_cost(order_total) == expected

Практический смысл здесь в том, что вы формулируете одну проверку: shipping_cost(order_total) == expected. Декоратор просто подставляет в нее разные пары значений. Если одна строка таблицы неверна, упадет только соответствующий запуск, а не весь набор целиком без деталей. Для арифметических правил это удобнее, чем писать отдельную функцию теста на каждую цифру.

Обратите внимание на одно решение в примере: отрицательная сумма обрабатывается в самой функции, но не попадает в эту параметризованную таблицу. Причина простая: там уже проверяется другое поведение — выброс исключения, а не числовой результат. Такой случай лучше вынести в отдельный тест с pytest.raises, чтобы одна таблица проверяла один тип ожидания.

Как сделать названия случаев читаемыми

Когда параметров немного, pytest сам сгенерирует имена запусков. Но как только в таблице появляются границы и похожие числа, полезно назвать случаи явно. Тогда в отчете будет видно не просто [1000-150], а смысловое имя вроде [at-1000]. Это ускоряет чтение падения: вам не нужно снова расшифровывать, что именно обозначает строка.

@pytest.mark.parametrize(
    "order_total, expected",
    [
        pytest.param(0, 300, id="zero-order"),
        pytest.param(999, 300, id="below-1000"),
        pytest.param(1000, 150, id="at-1000"),
        pytest.param(2999, 150, id="below-3000"),
        pytest.param(3000, 0, id="at-3000"),
        pytest.param(4500, 0, id="above-3000"),
    ],
)

Хорошие имена описывают правило, а не номер строки. case1 и case2 почти бесполезны, потому что при падении все равно придется открывать таблицу и вспоминать контекст. А вот below-3000 и at-3000 сразу показывают, проверяете ли вы внутренность диапазона или сам переход между диапазонами.

На практике такие имена особенно помогают при регрессии. Если после изменения функции падает только at-1000, вы почти сразу понимаете, что сломан знак сравнения на первом пороге. Это не заменяет анализ кода, но сокращает путь от красного теста к гипотезе о причине.

Как проверить границы и не потерять независимость тестов

Самая частая ошибка в табличных тестах — думать, что больше строк автоматически означает лучшее покрытие. Для функции с порогами важнее не количество чисел, а расположение чисел. Набор 1500, 2000 и 2500 почти ничего не скажет о границах, если вы не проверили 999, 1000, 2999 и 3000. Именно поэтому таблица из шести осмысленных точек обычно полезнее длинного случайного списка.

Есть и вторая тонкость: независимость запусков. В документации pytest отдельно сказано, что значения параметров передаются в тест как есть, без копирования. Для нашего примера это безопасно, потому что числа неизменяемы. Но если вы начнете передавать словари, списки или объекты и менять их прямо в тесте, состояние может «протечь» в следующий случай. Значит, для сложных параметров лучше либо не мутировать входные данные, либо создавать новый объект на каждый запуск.

Проверяемый результат этого учебного кейса такой: таблица ловит типичную граничную ошибку. Если испортить функцию и написать оба сравнения через > вместо >=, то случаи 1000 и 3000 упадут, а остальные могут остаться зелеными. В отчете вы увидите смысловые падения именно на порогах, например:

FAILED test_shipping.py::test_shipping_cost[at-1000] - assert 300 == 150
FAILED test_shipping.py::test_shipping_cost[at-3000] - assert 150 == 0

Это и есть главный практический вывод: параметризация полезна не сама по себе, а как способ собрать в одном месте граничные случаи одного правила. Если таблица составлена осмысленно, один короткий тест дает проверяемый сигнал о том, где именно нарушилась арифметика.

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

Курсы

10159
0,0
0 отзывов
Комплект курсов «Автоматизация тестов на Python» и «Python программист»
  • В любой момент
  • 4 месяца
  • Смешанный
  • Диплом / Сертификат
31 290 ₽34 775 ₽
-10%
Перейти на сайт