Тестова піраміда (Майк Кон) - модель розподілу тестів за рівнями:
/\ E2E / UI - мало: повільні, крихкі, дорогі
/ \
/----\ інтеграційні - середньо
/ \
/--------\ модульні (unit) - багато: швидкі, дешеві, точні
Логіка: чим вище рівень, тим тест повільніший, крихкіший і дорожчий у підтримці, але тим більше впевненості він дає, що система працює цілком. Тому основу складають швидкі модульні тести, а наскрізних - небагато, на головні сценарії.
«Тестовий трофей» (Кент Доддс), популярний у фронтенді:
🏆 E2E - кілька
----
| | інтеграційні - НАЙБІЛЬШЕ
|----|
unit - трохи
======
статичний аналіз - основа: типи, лінтери
Аргумент: модульні тести окремих функцій часто перевіряють деталі реалізації й не ловлять помилок взаємодії, а сучасні інструменти зробили інтеграційні тести досить швидкими. «Чим більше тести схожі на те, як використовують програму, тим більше впевненості вони дають».
Як це виглядає в Laravel-проєкті:
- статичний аналіз - PHPStan/Larastan, Pint: ловлять цілі класи помилок без жодного тесту;
- feature-тести (основа більшості Laravel-проєктів) - HTTP-запит до маршруту з реальною базою (
RefreshDatabase), фейками пошти й черг. Фактично інтеграційні, але досить швидкі; - unit-тести - для чистої логіки зі складними розгалуженнями: розрахунок ціни, парсери, правила;
- браузерні тести (Pest browser, Dusk) - для критичних сценаріїв з JavaScript.
Де архітектура має значення: якщо бізнес-логіка розмазана по контролерах і моделях, перевірити її можна лише дорогими тестами верхнього рівня. Винесена в окремі класи з явними залежностями - тестується дешево й точно.
Правильний розподіл - той, що дає впевненість у змінах за прийнятний час. Обидві моделі - орієнтири, а не закони: важливо, щоб набір тестів запускався швидко, був стабільним і ловив реальні регресії.
Докладніше в документації: Martin Fowler: The Practical Test Pyramid