Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. TDD: Red-Green-Refactor цикл в деталях
tdd_red_green_refactor

TDD: Red-Green-Refactor цикл в деталях

Цикл TDD пошагово: тест → реализация → рефакторинг. Когда писать тест первым, когда после. Прагматичный подход

TDD (Test-Driven Development) — подход где тест пишется ДО реализации. Red-Green-Refactor — цикл из 3 шагов.

Цель: Понять TDD цикл и научиться применять прагматично (не фанатично).

Red-Green-Refactor цикл

1. RED: Напишите failing test
   ↓
2. GREEN: Минимальный код для прохождения теста
   ↓
3. REFACTOR: Улучшите код без изменения поведения
   ↓
   Repeat

Пример: Todo Item с приоритетом

RED: Напишите failing test

# tests/test_todo_priority.py import pytest from todo_app.models import TodoItem def test_create_todo_with_priority(): """RED: Тест который пока не проходит""" todo = TodoItem(title="Buy milk", priority="high") assert todo.title == "Buy milk" assert todo.priority == "high"

Запуск:

pytest tests/test_todo_priority.py # ❌ FAILED: AttributeError: 'TodoItem' object has no attribute 'priority'

✅ RED — тест падает (это правильно!)

GREEN: Минимальный код

# todo_app/models.py class TodoItem: def __init__(self, title, priority=None): self.title = title self.priority = priority # ← Минимальная реализация

Запуск:

pytest tests/test_todo_priority.py # ✅ PASSED

✅ GREEN — тест проходит!

REFACTOR: Улучшите код

# todo_app/models.py from enum import Enum class Priority(Enum): LOW = "low" MEDIUM = "medium" HIGH = "high" class TodoItem: def __init__(self, title: str, priority: Priority = Priority.MEDIUM): self.title = title self.priority = priority def __repr__(self): return f"TodoItem(title={self.title!r}, priority={self.priority.value})"

Обновить тест:

def test_create_todo_with_priority(): """Тест с Enum""" todo = TodoItem(title="Buy milk", priority=Priority.HIGH) assert todo.title == "Buy milk" assert todo.priority == Priority.HIGH

Запуск:

pytest tests/test_todo_priority.py # ✅ PASSED (рефакторинг не сломал тест)

Цикл на практике: Todo сортировка по приоритету

Итерация 1: RED

def test_sort_todos_by_priority(): """RED: Сортировка ещё не реализована""" todos = [ TodoItem("Task 1", Priority.LOW), TodoItem("Task 2", Priority.HIGH), TodoItem("Task 3", Priority.MEDIUM), ] sorted_todos = sort_by_priority(todos) assert sorted_todos[0].priority == Priority.HIGH assert sorted_todos[1].priority == Priority.MEDIUM assert sorted_todos[2].priority == Priority.LOW

❌ NameError: name 'sort_by_priority' is not defined

Итерация 1: GREEN

# todo_app/sorting.py def sort_by_priority(todos): """Минимальная реализация""" priority_order = {Priority.HIGH: 0, Priority.MEDIUM: 1, Priority.LOW: 2} return sorted(todos, key=lambda t: priority_order[t.priority])

✅ PASSED

Итерация 2: RED (новый edge case)

def test_sort_with_same_priority(): """RED: Что если приоритет одинаковый?""" todos = [ TodoItem("Z Task", Priority.HIGH), TodoItem("A Task", Priority.HIGH), ] sorted_todos = sort_by_priority(todos) # Ожидаем алфавитную сортировку при одинаковом приоритете assert sorted_todos[0].title == "A Task" assert sorted_todos[1].title == "Z Task"

❌ FAILED: Z Task идёт первым

Итерация 2: GREEN

def sort_by_priority(todos): """Сортировка с fallback на title""" priority_order = {Priority.HIGH: 0, Priority.MEDIUM: 1, Priority.LOW: 2} return sorted(todos, key=lambda t: (priority_order[t.priority], t.title))

✅ PASSED

Итерация 2: REFACTOR

from dataclasses import dataclass, field @dataclass(order=True) class TodoItem: sort_index: int = field(init=False, repr=False) title: str priority: Priority = Priority.MEDIUM def __post_init__(self): priority_order = {Priority.HIGH: 0, Priority.MEDIUM: 1, Priority.LOW: 2} self.sort_index = (priority_order[self.priority], self.title) # Теперь сортировка встроенная def sort_by_priority(todos): return sorted(todos)

✅ Тесты проходят, код чище

Когда НЕ использовать TDD

❌ Плохо: Exploratory code

# Вы не знаете как работает библиотека import some_new_library # ❌ Писать тест бессмысленно — вы не знаете что ожидать def test_library_behavior(): result = some_new_library.do_something() assert result == ??? # Что проверять?

Решение: Сначала explore, потом тесты.

❌ Плохо: UI/визуальный код

# ❌ TDD для цвета кнопки бессмысленно def test_button_color(): button = render_button() assert button.color == "#FF0000" # Проверка субъективна

Решение: Visual regression tests или manual testing.

❌ Плохо: Throwaway code

# Одноразовый скрипт для миграции данных def migrate_users(): # ... # ❌ Тест не нужен — скрипт запустится один раз

Когда ИСПОЛЬЗОВАТЬ TDD

✅ Хорошо: Бизнес-логика

# ✅ TDD идеален для четкой бизнес-логики def test_calculate_subscription_price(): # Тест определяет требования price = calculate_subscription_price( plan="premium", users=5, annual=True ) assert price == 450 # $10/user/month * 12 months * 0.75 discount

✅ Хорошо: Утилиты

# ✅ TDD для pure functions def test_format_currency(): assert format_currency(1234.56, "USD") == "$1,234.56" assert format_currency(1234.56, "EUR") == "€1,234.56"

✅ Хорошо: API contracts

# ✅ TDD для API гарантирует контракт def test_create_user_api(): response = client.post("/users", json={"email": "test@test.com"}) assert response.status_code == 201 assert "id" in response.json() assert response.json()["email"] == "test@test.com"

Прагматичный TDD

# Гибридный подход # 1. Начните с теста для happy path def test_process_order_success(): result = process_order(user_id=1, item_id=10, quantity=2) assert result["status"] == "success" # 2. Напишите минимальный код def process_order(user_id, item_id, quantity): return {"status": "success"} # 3. Добавьте тесты для edge cases БЕЗ TDD def test_process_order_out_of_stock(): # Этот тест можно написать ПОСЛЕ реализации result = process_order(user_id=1, item_id=999, quantity=2) assert result["status"] == "error" assert "out of stock" in result["message"]

Проверьте свои знания

Вопросы ещё не добавлены

Вопросы для этой подтемы ещё не добавлены.

Далее: TDD Практика: Premium-подписка (Часть 1)