Какие основные инструменты и принципы unit-тестирования в Python

Ответ

В Python для unit-тестирования используются два основных фреймворка:

  1. unittest: Входит в стандартную библиотеку Python. Основан на классах и следует паттернам xUnit.
  2. pytest: Сторонний пакет, ставший де-факто стандартом. Отличается более простым синтаксисом, мощными фикстурами и богатой экосистемой плагинов.

Ключевые принципы unit-тестирования:

  • Изоляция: Каждый тест должен быть независим от других. Его результат не должен зависеть от порядка выполнения тестов.
  • Атомарность: Один тест проверяет одну конкретную единицу функциональности (например, один метод или функцию с определенным набором входных данных).
  • Детерминированность: При одинаковых входных данных тест всегда должен давать одинаковый результат (проходить или падать).

Пример с использованием pytest:

pytest позволяет писать тесты в виде простых функций, используя стандартный оператор assert для проверок.

# a_module.py
def add(a, b):
    """Простая функция сложения чисел."""
    if not isinstance(a, (int, float)) or not isinstance(b, (int, float)):
        raise TypeError("Оба аргумента должны быть числами")
    return a + b

# test_a_module.py
import pytest
from a_module import add

# Позитивный сценарий
def test_add_positive_numbers():
    assert add(2, 3) == 5

# Проверка граничных случаев
def test_add_zero():
    assert add(-1, 1) == 0

# Проверка вызова исключения
def test_add_raises_type_error_on_string_input():
    with pytest.raises(TypeError):
        add("a", 2)

Важные практики:

  • Мокинг (Mocking): Использование объектов-заглушек (например, с помощью unittest.mock или pytest-mock) для изоляции тестируемого кода от внешних зависимостей (базы данных, API).
  • Фикстуры (Fixtures): Механизм pytest для подготовки данных и состояния перед выполнением тестов и очистки после них (например, создание временной БД).
  • Покрытие кода (Code Coverage): Инструменты (например, pytest-cov) для анализа того, какая часть кода была выполнена во время тестов. Помогает выявить непротестированные участки.

Ответ 18+ 🔞

Смотри, ну вот объясняю тебе про тесты на питоне, как есть, без прикрас. Есть два главных фреймворка, которые все и используют, блядь.

Первый — это unittest, он прямо в питоне из коробки лежит, как гандон в кармане у школьника. Старый, на классах, скучный такой, но работает.

А второй — это pytest. Вот это, сука, настоящая магия! Все его юзают, потому что он проще, мощнее и с ним можно творить такое, что unittest просто обосрётся от зависти. Фикстуры там, плагины — овердохуища возможностей.

Главные правила, чтобы не быть мудаком:

  • Изоляция, ёпта! Каждый тест должен жить своей жизнью. Один сдох — остальные как ни в чём не бывало должны работать. Никакой зависимости друг от друга, блядь!
  • Атомарность. Один тест — одна проверка. Не надо в одной функции проверять, сложились ли числа, открылась ли база и не упал ли сервер. Это пиздец, а не тест.
  • Детерминированность. Запустил раз — упал. Запустил сто раз — должен сто раз упасть в том же самом месте, сука. Если он то проходит, то нет — это не тест, а лотерея какая-то, на хуй.

Вот смотри, как на pytest всё просто и красиво:

Пишем мы какую-то хрень, которая складывает числа.

# a_module.py
def add(a, b):
    """Простая функция сложения чисел."""
    if not isinstance(a, (int, float)) or not isinstance(b, (int, float)):
        raise TypeError("Оба аргумента должны быть числами")
    return a + b

А теперь тесты к этой хрени. Никаких классов, просто функции.

# test_a_module.py
import pytest
from a_module import add

# Ну тут всё просто, складываем два плюса
def test_add_positive_numbers():
    assert add(2, 3) == 5

# Граничный случай, минус один и один — ноль должен быть
def test_add_zero():
    assert add(-1, 1) == 0

# А вот это важно! Проверяем, что нахуй посылает, если передать не число
def test_add_raises_type_error_on_string_input():
    with pytest.raises(TypeError):
        add("a", 2)  # Вот тут должна вылететь ошибка, и тест пройдёт

Видишь? Никакой ебли с какими-то специальными методами. Написал assert, и всё, пиздец.

А теперь про крутые штуки, без которых нихуя не получится:

  • Мокинг. Это когда твоя функция лезет в базу данных или в интернет, а тебе это нахуй не нужно в тестах. Берёшь и подменяешь эту зависимость хуйнёй, которая делает вид, что она база данных. Библиотека unittest.mock или pytest-mock — твои лучшие друзья.
  • Фикстуры. О, это мощь pytest! Это такая штука, которая готовит для теста всё, что нужно: создаёт временную базу, наполняет её данными, а после теста всё подчищает, чтобы следов не осталось. Красота, блядь!
  • Покрытие кода. Вот ты написал тесты, а они, мудаки, проверили только 10% твоего кода. Как узнать? Ставишь pytest-cov, запускаешь, и он тебе рисует, какие строчки кода твои тесты вообще видели, а какие — нет. Полезная хуйня, чтобы не быть самоуверенным говнокодером.

Вот и вся наука. Пиши тесты, изолируй их, мокай что попало и смотри на покрытие. А то без этого получается как всегда: "Ой, а у меня на проде всё сломалось, блядь!".