← Назад к вопросам

Как организовываются параметризованные тесты в PyTest?

2.3 Middle🔥 142 комментариев
#Теория тестирования

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Организация параметризованных тестов в PyTest

В PyTest параметризация тестов — это мощный механизм для запуска одного теста с различными наборами входных данных и ожидаемых результатов. Это позволяет избежать дублирования кода и повышает покрытие тестирования. Основные способы организации параметризации:

1. Декоратор @pytest.mark.parametrize

Это самый распространённый и гибкий способ. Декоратор принимает два аргумента: список названий параметров и список значений.

import pytest

# Простейший пример: параметризация одного аргумента
@pytest.mark.parametrize("number", [1, 2, 3, 4, 5])
def test_is_positive(number):
    """Проверяем, что все числа положительные"""
    assert number > 0

# Параметризация нескольких аргументов
@pytest.mark.parametrize("input_value, expected", [
    (5, 25),     # 5² = 25
    (0, 0),      # 0² = 0
    (-3, 9),     # (-3)² = 9
    (2.5, 6.25)  # 2.5² = 6.25
])
def test_square(input_value, expected):
    """Тестируем возведение в квадрат"""
    result = input_value * input_value
    assert result == expected, f"Ошибка: {input_value}² = {result}, ожидалось {expected}"

2. Параметризация с помощью фикстур

PyTest позволяет создавать параметризованные фикстуры, которые могут передавать данные в тесты.

import pytest

# Создаем параметризованную фикстуру
@pytest.fixture(params=["chrome", "firefox", "edge"])
def browser(request):
    """Фикстура возвращает разные браузеры для тестирования"""
    browser_name = request.param
    print(f"\nЗапуск теста в браузере: {browser_name}")
    return browser_name

def test_browser_compatibility(browser):
    """Тест будет запущен для каждого браузера"""
    assert browser in ["chrome", "firefox", "edge"]
    
# Фикстура с более сложными данными
@pytest.fixture(params=[
    {"username": "user1", "password": "pass123", "role": "admin"},
    {"username": "user2", "password": "qwerty", "role": "user"},
    {"username": "guest", "password": "", "role": "guest"}
])
def user_credentials(request):
    """Возвращает различные наборы учетных данных"""
    return request.param

def test_authentication(user_credentials):
    """Тестируем аутентификацию с разными учетными данными"""
    assert "username" in user_credentials
    assert "role" in user_credentials

3. Динамическая параметризация

Иногда параметры нужно генерировать динамически во время выполнения.

import pytest
import math

# Генерация параметров через функцию
def generate_test_data():
    """Генерируем тестовые данные на лету"""
    test_cases = []
    for i in range(1, 6):
        test_cases.append((i, i*i))  # (число, квадрат числа)
    return test_cases

@pytest.mark.parametrize("num, square", generate_test_data())
def test_dynamic_parametrization(num, square):
    """Тест с динамически сгенерированными параметрами"""
    assert num * num == square

# Параметризация на основе внешних данных
import json
import os

def load_test_cases():
    """Загружаем тест-кейсы из JSON файла"""
    with open("test_data.json", "r") as f:
        return json.load(f)

@pytest.mark.parametrize("test_case", load_test_cases())
def test_with_external_data(test_case):
    """Тест с данными из внешнего источника"""
    assert test_case["input"] is not None
    assert test_case["expected"] is not None

4. Комбинированная параметризация

Можно применять несколько декораторов parametrize для создания декартова произведения параметров.

import pytest

@pytest.mark.parametrize("x", [1, 2, 3])
@pytest.mark.parametrize("y", [10, 20])
def test_cartesian_product(x, y):
    """Тест будет выполнен 3 × 2 = 6 раз"""
    result = x * y
    assert result == x * y  # Проверяем умножение
    print(f"{x} * {y} = {result}")

5. Параметризация с идентификаторами

Для лучшей читаемости результатов тестирования можно задавать понятные идентификаторы.

import pytest

# Использование параметра ids для понятных имен тестов
@pytest.mark.parametrize(
    "a, b, expected_sum",
    [
        (1, 2, 3),
        (5, -5, 0),
        (100, 200, 300),
        (0, 0, 0)
    ],
    ids=[
        "positive_numbers",
        "positive_and_negative", 
        "large_numbers",
        "zeros"
    ]
)
def test_addition_with_ids(a, b, expected_sum):
    """Тест сложения с понятными именами кейсов"""
    assert a + b == expected_sum

# Автоматическая генерация идентификаторов через функцию
def id_func(test_case):
    """Функция для генерации читаемых ID"""
    a, b, expected = test_case
    return f"{a}+{b}={expected}"

@pytest.mark.parametrize(
    "a, b, expected",
    [
        (1, 2, 3),
        (5, 5, 10),
        (10, -3, 7)
    ],
    ids=id_func  # Используем функцию для генерации ID
)
def test_with_custom_ids(a, b, expected):
    """Тест с кастомными идентификаторами"""
    assert a + b == expected

6. Параметризация классов

Можно параметризовать целые тестовые классы.

import pytest

@pytest.mark.parametrize("browser", ["chrome", "firefox", "safari"])
class TestLoginPage:
    """Весь класс будет параметризован для каждого браузера"""
    
    def test_login_button(self, browser):
        """Тест кнопки логина"""
        assert browser in ["chrome", "firefox", "safari"]
    
    def test_username_field(self, browser):
        """Тест поля username"""
        assert browser != ""  # Простая проверка
    
    def test_remember_me(self, browser):
        """Тест чекбокса 'Запомнить меня'"""
        # Здесь могла бы быть реальная логика тестирования UI
        print(f"Testing 'Remember me' in {browser}")

Ключевые преимущества параметризации в PyTest

  • Уменьшение дублирования кода: Один тест покрывает множество сценариев
  • Улучшенная читаемость: Все тестовые случаи видны в одном месте
  • Гибкость: Поддержка статических и динамических данных
  • Детальные отчёты: Каждый параметризованный запуск отображается отдельно
  • Комбинирование: Возможность комбинировать параметризацию с фикстурами и другими декораторами

Рекомендации по использованию

  1. Именуйте параметры осмысленно — это улучшает читаемость кода
  2. Используйте идентификаторы (ids) для сложных параметров
  3. Избегайте излишней параметризации — слишком много комбинаций замедлит тесты
  4. Группируйте связанные тест-кейсы — логически связанные данные должны быть вместе
  5. Используйте внешние источники данных для больших наборов тестовых данных

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