Тесты как часть культуры кода
Структуры в коде — Структуры данных; persistence — ORM.
Речь о качестве тестового кода, а не о "зачем тестировать". Хорошие тесты — такая же часть культуры, как имена и форматирование: они фиксируют модель MAPPER и страхуют рефакторинг.
Углублённый курс — тестирование, юнит-тесты, white-box.
Не тестируйте приватные методы
Приватное — деталь реализации. Тестируйте публичный контракт класса или use case. Если приватный метод настолько сложен, что "хочется теста" — вынесите его в отдельный класс с явным API.
Исключение — пересмотр границ.
Утверждения с содержанием
| Плохо | Лучше |
|---|---|
assertTrue(result) | assertEquals(ExpectedDiscount.TEN_PERCENT, order.discount()) |
assertNotNull(x) без проверки полей | Сравнение значимых полей value object |
Сравнение double на == | Допуск или BigDecimal / decimal |
Добавляйте описания в assert-сообщениях; заменяйте общие assertTrue на конкретные матчеры.
Моки и реальные объекты
Не мокайте всё подряд. Value objects, чистые функции, in-memory репозитории часто проще и стабильнее моков. Мок уместен на границе (HTTP, БД, почта).
Чрезмерные моки делают тест хрупким: любой рефакторинг внутренностей ломает 20 тестов, хотя поведение не менялось.
Flaky-тесты
Flaky — тест, который то проходит, то падает без изменения кода. Причины:
- зависимость от времени (
DateTime.Now, sleep); - порядок выполнения;
- общий mutable state;
- сеть и race.
Лечение — инъекция часов, изоляция данных, фикстуры, отказ от Thread.Sleep как "синхронизации".
Тестовые данные
- Реалистичные имена и значения — проще читать падение.
- Минимум лишнего в arrange — один сценарий на тест.
- Не ломать инкапсуляцию ради теста — фабрики в test scope, не
public set"для тестов".
Тест на каждый merge (CI) — культура команды, не личный ритуал.
Тесты вместо комментариев
Если комментарий объясняет поведение, часто лучше характеризационный тест (легаси). Комментарий устаревает; тест в CI — нет.
Связь с цикломатической сложностью
Чем выше M у функции, тем больше независимых сценариев нужно покрыть (статья 2). Если покрытие гонят "ради процента", а assert пустые — культура кода не растёт.
Краткий чек-лист
- Тест называется как сценарий:
CancelOrder_WhenPaid_Throws. - Один логический assert на поведение (допускаются несколько assert на один объект).
- Нет
sleepи глобального state между тестами. - Рефакторинг домена — тесты зелёные без правки ожиданий "потому что поменяли private".
Указатель тем — Справочник тем чистого кода. Дальше: Исключения.