Короткий ответ
Property-based тестирование полезно для кода с чёткими инвариантами и большим пространством входных данных (парсеры, сериализация/десериализация, математические операции), но не должно полностью заменять example-based тесты, которые лучше документируют конкретные бизнес-сценарии и граничные случаи, понятные человеку.
Как это работает подробнее
Вместо фиксированных примеров hypothesis генерирует множество случайных входных данных по описанной стратегии и проверяет, что заданное свойство (инвариант) выполняется для всех них — например, что decode(encode(x)) == x для любого x из определённого диапазона. При падении hypothesis автоматически минимизирует (shrinking) контрпример до простейшего воспроизводимого случая.
Сравнение
- Компромисс. Property-based тесты находят неочевидные граничные случаи, которые человек не всегда придумает вручную, но требуют больше времени на формулировку инвариантов и могут давать более медленные и иногда недетерминированные (по времени выполнения) прогоны. Критерий выбора: внедрять точечно для модулей с высокой ценой ошибки и чёткими инвариантами, сохраняя example-based тесты для документирования конкретных бизнес-правил и регрессионных случаев, найденных в production.
Пример кода
testing_example_325.py
from hypothesis import given, strategies as st
def normalize_phone(raw: str) -> str:
digits = "".join(ch for ch in raw if ch.isdigit())
return digits[-10:]
@given(st.text(alphabet="0123456789 -()", min_size=10, max_size=20))
def test_normalize_phone_always_returns_exactly_10_digits(raw):
result = normalize_phone(raw)
assert len(result) <= 10
assert result.isdigit() or result == ""Что использовать на практике
- Практика. Хорошие кандидаты — чистые функции с математическими или структурными инвариантами: сериализация, нормализация данных, арифметика с деньгами, сортировки. Плохие кандидаты — код с тяжёлыми побочными эффектами (реальные сетевые вызовы, запись в БД), где случайная генерация большого числа запусков дорога и малоинформативна без дополнительной инфраструктуры.
Подводные камни
- Риск. Пытаться описать property-тестом код, у которого нет чёткого формулируемого инварианта, и в итоге писать сложную, малопонятную стратегию генерации данных ради сомнительной пользы. Выбрасывать существующие example-based тесты важных бизнес-кейсов в пользу property-тестов, теряя читаемую документацию конкретных сценариев для новых членов команды.