Короткий ответ
Сначала стоит покрыть существующее поведение модуля характеризационными тестами (characterization tests), фиксирующими текущее поведение как есть, а уже затем вносить изменения — это даёт сеть безопасности и подтверждает, что ничего непредвиденное не сломалось.
Как это работает подробнее
Характеризационный тест не проверяет «правильность» поведения в абстрактном смысле — он фиксирует, что модуль делает прямо сейчас, на реальных или приближенных к реальным входных данных. Если после правки такой тест ломается, это сигнал, что поведение изменилось, и нужно осознанно решить, ожидаемо ли это, вместо того чтобы узнавать об этом от пользователей в продакшене.
Пример кода
example.py
# Шаг 1: фиксируем текущее поведение тестом, прежде чем менять код
def test_calculate_shipping_current_behavior():
# Документирует фактическое (возможно, неидеальное) поведение,
# чтобы при рефакторинге заметить случайное изменение результата
assert calculate_shipping(weight_kg=0, region="RU") == 0
assert calculate_shipping(weight_kg=-5, region="RU") == 0 # баг? фиксируем как есть
assert calculate_shipping(weight_kg=10, region="RU") == 350Что использовать на практике
- Практика. Для изменений стоит выбрать минимально инвазивный подход: сначала добавить тесты вокруг кода, который планируется менять (не переписывая его), затем вносить изменения маленькими шагами, перезапуская тесты после каждого шага. Если модуль имеет побочные эффекты (запись в БД, сетевые вызовы), для тестов стоит использовать подставные объекты (моки) или тестовую базу данных.
Подводные камни
- Риски. Частая ошибка — сразу переписывать «страшный» код целиком «по-правильному», без тестов, полагаясь на ручную проверку — это резко повышает риск незаметно изменить граничное поведение, на которое уже полагаются другие части системы. Другая ошибка — пытаться покрыть тестами сразу весь модуль целиком вместо того, чтобы сфокусироваться на участке, который реально меняется. Также вредно воспринимать странное поведение как заведомый баг и «исправлять» его попутно, не убедившись, что на него никто не полагается.