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

Как использовать unit тест с параметрами в pytest?

1.7 Middle🔥 211 комментариев
#Тестирование

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

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

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

Параметризованные тесты в pytest

Параметризация позволяет запустить один тест с разными наборами данных, избежав дублирования кода. Это мощный инструмент для тестирования граничных случаев.

Базовая параметризация: @pytest.mark.parametrize

import pytest

@pytest.mark.parametrize("input,expected", [
    (2, 4),
    (3, 9),
    (4, 16),
    (-1, 1),
    (0, 0),
])
def test_square(input, expected):
    assert input ** 2 == expected

Это эквивалентно написанию 5 отдельных тестов.

Параметризация нескольких аргументов

@pytest.mark.parametrize("username,password,is_valid", [
    ("admin", "secret123", True),
    ("admin", "wrong", False),
    ("guest", "guest", True),
])
def test_login(username, password, is_valid):
    result = authenticate(username, password)
    assert result.is_valid == is_valid

Использование ids для читаемых названий

@pytest.mark.parametrize(
    "user_id,expected_role",
    [(1, "admin"), (2, "user"), (3, "moderator")],
    ids=["admin_user", "regular_user", "moderator_user"]
)
def test_user_roles(user_id, expected_role):
    user = get_user(user_id)
    assert user.role == expected_role

ids делают названия тестов более информативными.

Вложенная параметризация

@pytest.mark.parametrize("x", [1, 2, 3])
@pytest.mark.parametrize("y", ["a", "b"])
def test_multiple_params(x, y):
    # Выполнится 3 * 2 = 6 раз
    assert x > 0
    assert y in ["a", "b"]

Декартово произведение параметров.

Тестирование валидации

def validate_email(email: str) -> bool:
    return "@" in email and "." in email

@pytest.mark.parametrize(
    "email,valid",
    [
        ("user@example.com", True),
        ("invalid.email", False),
        ("@example.com", False),
    ],
    ids=["valid", "no_at", "no_local"]
)
def test_email_validation(email, valid):
    assert validate_email(email) == valid

Параметризация с fixtures (indirect)

@pytest.fixture
def user(request):
    user_data = request.param
    return create_user(**user_data)

@pytest.mark.parametrize(
    "user",
    [
        {"name": "Alice", "role": "admin"},
        {"name": "Bob", "role": "user"},
    ],
    indirect=True
)
def test_user_permissions(user):
    if user.role == "admin":
        assert user.can_delete_users

Hypothesis для property-based тестирования

from hypothesis import given, strategies as st

@given(st.integers(min_value=0, max_value=100))
def test_factorial_properties(n):
    result = factorial(n)
    assert result >= 1

Тестирование обработки ошибок

@pytest.mark.parametrize(
    "invalid_input,expected_error",
    [(None, ValueError), ("", ValueError), (-1, ValueError)]
)
def test_parse_invalid_input(invalid_input, expected_error):
    with pytest.raises(expected_error):
        parse_number(invalid_input)

Best practices

1. Используйте ids для читаемости — делает тесты понятнее в отчётах.

2. Группируйте связанные тесты — отделяйте valid и invalid случаи.

3. Избегайте слишком много параметров — если больше 3-4, используйте объекты.

4. Информативные сообщения об ошибках — помогают быстро найти проблему.

Параметризация в pytest — это стандартный способ тестирования граничных случаев без дублирования кода.