Skip to content

Testing

КРИТИЧНО: Тестовая БД

НИКОГДА не запускать тесты с RefreshDatabase на рабочей БД.

  • phpunit.xml ОБЯЗАН содержать <env name="DB_DATABASE" value="{project}_test"/>
  • Тестовая БД создаётся вручную: CREATE DATABASE catalog_test; + CREATE EXTENSION IF NOT EXISTS postgis;
  • Перед первым запуском тестов — убедиться что тестовая БД существует и extensions установлены
  • RefreshDatabase откатывает ВСЕ миграции и пересоздаёт схему — на рабочей БД это = потеря всех данных

Стратегия

ТипЧто тестируетПриоритет
Feature testsHTTP responses, роуты, формы, APIВысший — делать всегда
Unit testsСервисы со сложной логикой (расчёты, формулы)Средний — для критичной логики
Visual (Playwright)Рендеринг ключевых страницНизкий — для финальной проверки

Структура

tests/
├── Feature/
│   ├── PageTest.php              — статические страницы → 200
│   ├── {Section}Test.php         — каждая группа роутов
│   ├── RedirectTest.php          — 301 редиректы
│   ├── Api{Entity}Test.php       — API endpoints
│   └── SitemapTest.php           — sitemap содержит все URL
├── Unit/
│   └── {Service}Test.php         — сервисы с логикой
└── TestCase.php

Feature Tests

Что тестировать обязательно

  • Каждый публичный URL → 200
  • 301 редиректы → правильный destination
  • POST формы → валидация (422 на невалидные данные) + сохранение (201/302)
  • API rate limiting → 429 после лимита
  • 404 на несуществующие URL
  • Наличие ключевых элементов на странице (h1, breadcrumbs, title)

Правила

  • RefreshDatabase trait — чистая БД на каждый тест
  • $this->seed() в setUp — если тесты зависят от данных из seeders
  • Один assert на одно поведение — не мешать проверки в одном тесте
  • Именование: test_{что_тестируем}_{ожидаемый_результат} — например test_contact_form_validates_phone

Checklist для нового роута

  1. GET → 200
  2. GET несуществующий slug → 404
  3. Наличие title, h1 в response
  4. Если форма — POST с валидными данными → success
  5. Если форма — POST с невалидными данными → 422/redirect с errors
  6. Если 301 — проверить destination

Unit Tests

Когда писать

  • Сервис с расчётами (калькулятор, формулы, скидки)
  • Сервис с ветвлением (разные стратегии по условию)
  • Utility/helper с edge cases

Когда НЕ писать

  • Простой CRUD без логики — покрывается feature тестом
  • Eloquent relations — это ответственность фреймворка
  • Прямые вызовы внешних API — мокать, не тестировать реальный API

Правила

  • Тестировать поведение, не реализацию — если рефакторинг меняет внутренности, тест не должен ломаться
  • Мокать внешние зависимости (API, email, telegram) — Mail::fake(), Queue::fake()
  • НЕ мокать БД — использовать RefreshDatabase с реальными запросами

Playwright (Visual)

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

  • Финальная проверка ключевых страниц после крупных изменений
  • Проверка JS-функциональности (формы, калькуляторы, модальные окна)
  • Сравнение с ожидаемым результатом после миграции

Процесс

  1. browser_navigate → URL
  2. browser_snapshot → проверить ключевые элементы
  3. browser_console_messages → убедиться что нет JS ошибок
  4. browser_close — всегда закрывать после проверки

Ключевые страницы для проверки

  • Главная
  • Категория услуг (типовая)
  • Детальная страница (типовая)
  • Контакты / форма
  • Калькулятор (если есть JS-логика)

Sitemap Validation

  • Получить sitemap → проверить что каждая сущность из БД присутствует
  • Все URL из sitemap → 200 (не 404, не 500)
  • Сравнение с предыдущей версией sitemap — нет потерянных URL

Запуск тестов

Всегда через Docker:

  • Все тесты: docker exec {container} php artisan test
  • По классу: docker exec {container} php artisan test --filter=PageTest
  • Параллельно: docker exec {container} php artisan test --parallel

Anti-patterns

ПаттернПроблемаРешение
Нет тестов на публичные URLСломанная страница уезжает в prodFeature test на каждый роут
Mock БД вместо реальных запросовТесты проходят, но миграция сломанаRefreshDatabase
Тест зависит от порядкаFlaky testsКаждый тест — изолирован
Один тест на 10 assertionsНепонятно что сломалосьОдин assert = одно поведение
Тест проверяет реализациюЛомается при рефакторингеТестировать поведение
Нет теста на 301 redirectsRedirect потерян → SEO пострадалRedirectTest
dd() / dump() в тестеОстаётся в коде$this->assert*()

Внутренняя база знаний студии