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

Пишешь ли тесты после кода

1.7 Middle🔥 91 комментариев
#Основы Java

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

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

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

Тестирование: TDD vs Unit Tests

Это важный вопрос о методологии разработки. Дам честный ответ, основанный на опыте.

Идеальный подход: Test-Driven Development (TDD)

Теория гласит: пиши тесты ДО написания кода. Процесс:

  1. RED - напиши падающий тест
  2. GREEN - напиши минимальный код для прохождения
  3. REFACTOR - улучши без изменения поведения
@Test
public void shouldCalculateSum() {
    Calculator calc = new Calculator();
    int result = calc.add(2, 3);
    assertEquals(5, result);
}

// Сначала тест падает, потом пишешь:
public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }
}

Преимущества TDD:

  • Гарантированное покрытие - весь код имеет тесты
  • Лучший дизайн - API проектируется с позиции пользователя
  • Меньше багов - проблемы выявляются сразу
  • Уверенность в рефакторинге - тесты защищают от регрессии
  • Живая документация - тесты показывают как использовать код

Реальная практика: гибридный подход

В production-коде часто используют комбинацию:

1. TDD для сложной бизнес-логики

// Сложная логика скоринга - пишу тест ДО кода
@Test
public void shouldCalculateScoreCorrectlyWithBonus() {
    ScoreCalculator calc = new ScoreCalculator();
    int score = calc.calculate(100, true);  // bonus
    assertEquals(150, score);
}

public class ScoreCalculator {
    public int calculate(int baseScore, boolean hasBonus) {
        return hasBonus ? baseScore + 50 : baseScore;
    }
}

2. Unit-тесты после для стандартного кода

// Простой CRUD метод - сначала пиши код
public User getUserById(long id) {
    return userRepository.findById(id)
        .orElseThrow(() -> new UserNotFoundException(id));
}

// Потом тест
@Test
public void shouldThrowExceptionWhenUserNotFound() {
    assertThrows(UserNotFoundException.class, () -> {
        service.getUserById(999);
    });
}

Мой подход (10+ лет опыта)

Я практикую TDD для критичного функционала и Unit tests ПОСЛЕ для стандартного кода:

  • TDD: платежные системы, расчёты, алгоритмы
  • Tests after: CRUD, маппинг, просто getters/setters

Критерий выбора:

  • Если логика может иметь edge cases → TDD
  • Если логика простая и понятная → тест после

Когда тесты ОБЯЗАТЕЛЬНЫ (даже простые)

// ❌ Никогда не оставляй без тестов:

// 1. Публичное API
public List<User> findByRole(UserRole role) { ... }

// 2. Бизнес-логика
public BigDecimal calculateDiscount(Customer c) { ... }

// 3. Обработка ошибок
public void validateEmail(String email) { ... }

// 4. Многопоточный код
public synchronized void updateCache() { ... }

Хорошая практика: покрытие тестами

// Структура проекта
src/main/java/
  └─ com/example/
     ├─ domain/
     ├─ service/
     └─ controller/

src/test/java/
  └─ com/example/
     ├─ domain/      // 95%+ покрытие (критично)
     ├─ service/     // 90%+ покрытие
     └─ controller/  // 70%+ покрытие (много мокируется)

Минус "тестов после"

// Когда пишешь код БЕЗ предварительных тестов,
// часто упускаешь edge cases:

public int divide(int a, int b) {
    return a / b;  // Забыл проверить b == 0!
}

// С TDD эта ошибка была бы выявлена сразу:
@Test
public void shouldThrowExceptionOnDivideByZero() {
    assertThrows(IllegalArgumentException.class, () -> {
        calc.divide(10, 0);
    });
}

Инструменты и метрики

# JaCoCo для отчётов покрытия
./gradlew jacocoTestReport

# Минимум 80-90% для production
<limit>
    <element>LINE</element>
    <includes>
        <include>*</include>
    </includes>
    <excludes>
        <exclude>*Test</exclude>
    </excludes>
    <minimum>0.85</minimum>
</limit>

Мой совет

  1. Всегда пиши тесты (или до, или после)
  2. TDD для сложной логики - это просто мудро
  3. Не занимайся религиозными войнами - обе стороны работают
  4. Главное - покрытие есть, а не когда оно написано
  5. Code review должен требовать тестов - это ответственность команды

Заключение

Практикую комбинированный подход:

  • TDD для сложных алгоритмов и бизнес-логики
  • Unit tests after для стандартного CRUD кода
  • Всегда ≥90% покрытие для critical path
  • CI/CD проверяет покрытие - непройти нельзя

Идеального ответа нет - выбирайте подход под вашу команду и проект.