Как написать unit-тест с pytest?python-58

Pytest — это популярный фреймворк для тестирования Python-кода. Вот подробное руководство по написанию unit-тестов:

1. Установка pytest

pip install pytest

2. Базовая структура теста

Тесты в pytest — это обычные функции, начинающиеся с test_ (или методы в классах, начинающихся с Test).

# test_example.py
def test_addition():
    assert 1 + 1 == 2  # Простейший assert (проверка)

3. Фикстуры — повторно используемые ресурсы

Фикстуры позволяют создавать переиспользуемые компоненты для тестов.

import pytest

@pytest.fixture
def sample_data():
    return {"a": 1, "b": 2}

def test_sample_data(sample_data):  # Фикстура автоматически внедряется
    assert sample_data["a"] == 1

4. Параметризация тестов

Позволяет запускать один тест с разными входными данными.

import pytest

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

5. Проверка исключений

Для проверки, что код вызывает ожидаемое исключение:

import pytest

def test_division_by_zero():
    with pytest.raises(ZeroDivisionError):
        result = 1 / 0

6. Маркеры — метки для тестов

Позволяют помечать тесты для выборочного запуска.

@pytest.mark.slow
def test_long_operation():
    # Тест с длительным выполнением
    assert some_long_operation() == expected_result

Запуск только помеченных тестов:

pytest -m slow

7. Мокирование — подмена реальных объектов

Используем unittest.mock для изоляции тестируемого кода:

from unittest.mock import Mock

def test_api_call():
    mock_response = Mock(status_code=200, json=lambda: {"key": "value"})
    assert mock_response.status_code == 200

8. Плагины и расширения

Популярные плагины:

  • pytest-cov: проверка покрытия кода тестами
  • pytest-xdist: параллельное выполнение тестов
  • pytest-asyncio: тестирование asyncio-кода

9. Best Practices

  1. Тесты должны быть изолированными
  2. Имена тестов должны быть описательными
  3. Избегайте сложной логики в тестах
  4. Стремитесь к высокому покрытию (но не 100% ради 100%)
  5. Тестируйте граничные случаи (edge cases)

Пример комплексного теста

import pytest
from myapp.calculator import Calculator

@pytest.fixture
def calc():
    return Calculator()

@pytest.mark.parametrize("a,b,expected", [
    (1, 2, 3),
    (-1, -1, -2),
    (0, 0, 0)
])
def test_add(calc, a, b, expected):
    assert calc.add(a, b) == expected

def test_divide_by_zero(calc):
    with pytest.raises(ValueError, match="Cannot divide by zero"):
        calc.divide(10, 0)

Резюмируем

Pytest предлагает мощный, но простой инструментарий для unit-тестирования. Ключевые особенности: фикстуры для управления зависимостями, параметризация для тестирования множества сценариев, богатая экосистема плагинов и понятный синтаксис. Начните с простых тестов и постепенно осваивайте более сложные возможности фреймворка.