<? phpukraine СПІВБЕСІДИ
⌕Пошук по платформі
ТЕСТУВАННЯ · MIDDLE ЧАСТО ПИТАЮТЬ

Що таке TDD і як ви застосовуєте його на практиці?

TDD це цикл з трьох кроків: написати маленький тест, що падає з очікуваної причини (red), найпростішим кодом зробити його зеленим (green), прибрати дублювання й покращити дизайн під захистом тестів (refactor). Головна користь у фідбеку на дизайн, покриття тут лише побічний ефект: код, який важко протестувати першим, зазвичай має забагато залежностей. Найкраще працює для доменної логіки з чіткими правилами, гірше для дослідницького коду й UI.

Ви пишете тести до коду чи після?
Що означає red, green, refactor і навіщо крок з червоним тестом?
Чим лондонська школа TDD відрізняється від класичної?
Коли TDD не допомагає, а заважає?
TDD red green refactor outside-in Detroit London school

Test-driven development описав Кент Бек (Kent Beck) у книжці «Test-Driven Development: By Example» (2002). Цикл має три кроки. Red: написати маленький тест на одну нову поведінку й побачити, що він падає, причому з очікуваної причини. Green: найпростішим кодом зробити тест зеленим, не думаючи поки про красу. Refactor: прибрати дублювання, дати назви, винести константи, поки всі тести зелені. Потім наступний тест, і цикл повторюється кожні кілька хвилин.

Червоний крок здається формальністю, але саме він робить тест надійним. Тест, який ніколи не був червоним, може нічого не перевіряти: асерт порівнює значення сам із собою, тест не той файл, метод названо з одруківкою. Побачивши падіння «очікували 0, отримали 50», ви знаєте, що тест дивиться на правильну річ. Рефакторинг теж не можна пропускати: без нього «найпростіший код» з кожним циклом обростає частковими випадками.

Найбільше TDD дає як фідбек на дизайн. Якщо перший тест на клас вимагає піднімати контейнер, базу й пів десятка моків, це видно ще до того, як написано код, і клас одразу отримує залежності через конструктор, час параметром і вузькі інтерфейси. Тому TDD природно веде до чистих доменних обʼєктів, які легко перевірити.

Існують дві школи. Класична (її звуть Detroit або Chicago) іде зсередини назовні: починає з доменних обʼєктів, бере справжніх сусідів і перевіряє стан. Лондонська, описана Стівом Фріменом і Натом Прайсом у «Growing Object-Oriented Software, Guided by Tests», іде ззовні всередину: приймальний тест на сценарій, потім клас верхнього рівня, а ще неіснуючих сусідів підміняють моками, щоб відкрити їхні інтерфейси. У Laravel-проєкті поширений гібрид: червоний feature-тест сценарію зверху і класичні TDD-цикли для домену під ним.

У TDD є чесні межі. Для дослідження незнайомого API чи бібліотеки роблять спайк, прототип без тестів, і викидають його. Верстку, склеювальний код і конфігурацію вигідніше перевіряти feature-тестами після. А найдешевша точка входу в TDD у будь-якому проєкті це баги: спершу тест, що відтворює баг і падає, потім виправлення.

// Крок 1, red: тест на поведінку, якої ще немає.
// Спершу падає, бо класу Delivery немає. Із заглушкою `return 50;`
// падає вже на 2000 гривнях: це і є очікувана причина.
it('is free from 2000 hryvnias', function (int $sum, int $price) {
    expect((new Delivery)->price($sum))->toBe($price);
})->with([
    'на гривню менше' => [1999, 50],
    'рівно на порозі' => [2000, 0],
]);

// Крок 2, green: найпростіший код, що проходить тест.
final class Delivery
{
    public function price(int $sum): int
    {
        return $sum >= 2000 ? 0 : 50;
    }
}

// Крок 3, refactor: на зеленому прибираємо магічні числа.
// Тест не змінюється, і саме він гарантує, що поведінка та сама.
final class DeliveryRefactored
{
    private const FREE_FROM = 2000;
    private const PRICE = 50;

    public function price(int $sum): int
    {
        return $sum >= self::FREE_FROM ? 0 : self::PRICE;
    }
}

// Далі новий цикл: наступний тест на наступне правило.
Точний цикл red, green, refactor і сенс червоного кроку: переконатися, що тест справді перевіряє нове і падає з тієї причини, яку ви очікуєте.
Маленькі кроки: один тест на одну нову поведінку, найпростіша реалізація, рефакторинг лише на зеленому.
Дві школи: класична (Detroit, Chicago, Кент Бек) тестує стан справжніми обʼєктами зсередини назовні, лондонська (Фрімен і Прайс) іде ззовні всередину з моками сусідів і перевіркою взаємодій.
Чесні межі: TDD не підходить для спайків і дослідження незнайомого API, де спершу пишуть прототип і викидають його; UI і склеювальний код вигідніше покривати feature-тестами після.
Що TDD впливає на дизайн: залежності через конструктор, чисті функції, малі класи.
Казати «пишу тести першими» й описувати написання всіх тестів наперед, а потім усього коду: це не TDD, цикл мусить бути коротким.
Пропускати червоний крок: тест, який ніколи не був червоним, може нічого не перевіряти (одруківка в назві методу, асерт на сам себе).
Пропускати рефакторинг: після green код лишається найпростішим, і через місяць це купа частковостей під кожен тест.
Писати в червоному кроці величезний тест на весь сценарій, через що до green іде година й десяток класів.
Видавати TDD за релігію («без TDD код не можна писати») або, навпаки, за марнування часу, без розмови про контекст.
ПОРАДА

Опишіть один реальний цикл з вашої практики: «правило про поріг безкоштовної доставки: спершу тест на 1999 і 2000, червоний, бо методу немає; потім `return $sum >= 2000 ? 0 : 50`; потім рефакторинг, винесли поріг у константу». Конкретний цикл звучить переконливіше за визначення, а слова «спершу побачив, що тест падає з правильної причини» показують розуміння сенсу.

оновлено 8 жовтня 2026 · ліцензія CC-BY-SA-4.0 Знайшли неточність? Напишіть →
ПЕРЕВІРТЕ СЕБЕ

TDD працює короткими циклами на одну поведінку. Червоний крок доводить, що тест справді перевіряє нове і падає з правильної причини. Рефакторинг іде лише на зеленому. Для дослідження чужого API роблять спайк без тестів, а TDD починають, коли зрозуміло, яку поведінку треба отримати.