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

Всегда ли нужны тесты

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

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

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

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

Нужны ли тесты всегда?

Это частый вопрос в индустрии, и ответ не чёрно-белый: тесты нужны почти всегда, но степень их покрытия зависит от контекста проекта.

Когда тесты критичны

Production-среда и критичные системы:

  • Финансовые транзакции (каждый баг = потеря денег)
  • Медицинские системы (каждая ошибка может стоить жизни)
  • Системы с SLA (требуются гарантии)
  • Долгоживущие проекты (техдолг растёт без тестов)

Сложная бизнес-логика:

# Расчёты скидок, комиссий, налогов — всегда нужны тесты
def calculate_price(base_price: float, discount: float, tax_rate: float) -> float:
    """Даже простая функция должна протестирована для граничных случаев"""
    discounted = base_price * (1 - discount / 100)
    with_tax = discounted * (1 + tax_rate / 100)
    return round(with_tax, 2)

# Граничные случаи:
# - discount = 0, 100 (полная скидка)
# - negative values (ошибочные данные)
# - precision (округление)

Публичные API и библиотеки:

  • Клиенты зависят от вашего кода
  • Любое изменение API может сломать их
  • Регрессионные тесты предотвращают неожиданные breaking changes

Когда можно обойтись без полного покрытия

MVP и экспериментальный код:

# Быстрый прототип для валидации идеи
# Здесь фокус на скорости разработки, не стабильности
def get_trending_posts():
    return requests.get(https://api.example.com/trending).json()

Простая логика представления (UI/шаблоны):

  • Рендеринг HTML без сложной логики
  • Фронтенд без бизнес-правил
  • UI слой можно тестировать инструментами E2E (Playwright, Cypress)

Конфигурационные файлы:

# Конфиг-файл — обычно достаточно manual testing
CONFIG = {
    database_url: postgresql://...,
    debug: True,
}

Мой подход: прагматичное тестирование

Слои приложения и тестовое покрытие:

  1. Domain/Business Logic: 90-100% покрытие

    # Сложная логика = максимум тестов
    class OrderService:
        def calculate_total(self, items: List[Item]) -> Money:
            pass  # Граничные случаи, скидки, налоги
    
  2. Application/Use Cases: 80-90% покрытие

    # Orchestration logic
    class CreateOrderUseCase:
        def execute(self, command: CreateOrderCommand) -> OrderDTO:
            pass  # Happy path + error cases
    
  3. Infrastructure/External APIs: 60-80% покрытие

    # Внешние зависимости — мокируем и тестируем
    class PaymentGateway:
        def charge(self, card: str, amount: Money) -> TransactionId:
            pass  # Тестируем с VCR.py cassettes
    
  4. Presentation/Handlers: 50-70% покрытие

    # UI слой — основной юнит-тесты, E2E для критичных flows
    @router.post(/orders)
    def create_order(request: CreateOrderRequest):
        pass
    

Техники эффективного тестирования

Pyramidal Testing (тестовая пирамида):

      E2E (5-10%)
    Integration (15-25%)
  Unit (70-80%)

Много дешёвых юнит-тестов, меньше интеграционных, ещё меньше E2E.

Test-Driven Development (TDD):

# 1. RED — напишу падающий тест
def test_order_total_with_discount():
    order = Order(items=[Item(10)], discount=10)  # 10%
    assert order.total == 9.0  # Falls

# 2. GREEN — минимальный код
class Order:
    def __init__(self, items, discount=0):
        self.items = items
        self.discount = discount
    
    @property
    def total(self):
        subtotal = sum(i.price for i in self.items)
        return subtotal * (1 - self.discount / 100)

# 3. REFACTOR — улучшаю сохраняя зелёные тесты

Когда НЕ писать тесты (редко, но бывает)

  1. Одноразовые скрипты (миграция данных, backfill)
  2. Spike/прототипирование (потом удалится)
  3. Код, который сразу выбросишь (но лучше не полагаться на это)

Вывод

Проверь себя вопросом:

  • Может ли баг в этом коде стоить денег? → Нужны тесты
  • Зависит ли от этого код других? → Нужны тесты
  • Будешь ли развивать это дальше? → Нужны тесты
  • Это throwaway код? → Можно обойтись

На production я пишу тесты для:

  • Всей бизнес-логики (90%+)
  • Критичных flows (e2e)
  • API контрактов

Не тестирую:

  • Банальный CRUD без логики
  • Зависимости, которые уже протестированы (requests, sqlalchemy)
  • UI ренденю (делаю визуальное тестирование)

Тесты — это не overhead, это страховка. На проектах, где я видел 0% тестов, через год техдолг зашкаливал, а в production падали баги каждую неделю.