Laravel TDD Workflow — что это 🧪
Этот навык задаёт стандартный workflow для разработки через тестирование (TDD) в Laravel-приложениях. Он подходит для команд, использующих PHPUnit или Pest, и нацелен на покрытие 80%+ (unit + feature). Описанные приёмы покрывают все основные сценарии: от тестирования Eloquent-моделей и политик до проверки внешних HTTP-сервисов и Inertia.js-страниц.
Навык подходит для:
- Разработчиков, внедряющих TDD в Laravel-проекты
- Команд, желающих стандартизировать подходы к тестам
- Ситуаций, когда нужно быстро разобраться с Red-Green-Refactor циклами, фикстурами, фабриками и моками
Как работает ⚙️
Цикл Red-Green-Refactor
- Red — напиши тест, который падает
- Green — реализуй минимальный код, чтобы тест прошёл
- Refactor — улучши код, не ломая тестов
Уровни тестирования 📊
- Unit — чистая бизнес-логика: value objects, сервисы, хелперы
- Feature — HTTP-эндпоинты, аутентификация, валидация, политики
- Integration — связки: база + очередь + внешние сервисы
Выбор уровня зависит от проверяемого сценария:
- Чистая логика → Unit
- HTTP и права доступа → Feature
- Сквозные сценарии с БД/очередями → Integration
Стратегия работы с базой данных 🗄️
RefreshDatabase — дефолтный выбор для Feature и Integration тестов. Миграции выполняются один раз за сессию, каждый тест оборачивается в транзакцию (если БД поддерживает). Для in-memory SQLite миграции бегут перед каждым тестом
DatabaseTransactions — когда схема уже накатана, нужен только rollback
DatabaseMigrations — если требуется полная переустановка схемы каждый раз (долго)
Выбор фреймворка 🎯
- Для новых тестов — Pest (более лаконичный синтаксис)
- PHPUnit — только если проект уже на нём стандартизирован, или нужна специфичная тулза
Примеры тестов
PHPUnit (Feature): тест владельца, создающего проект
$user = User::factory()->create();
$response = $this->actingAs($user)->postJson('/api/projects', ['name' => 'New Project']);
$response->assertCreated();
$this->assertDatabaseHas('projects', ['name' => 'New Project']);
Pest (Feature): тот же сценарий, гибче синтаксис
test('owner can create project', function () {
$user = User::factory()->create();
$response = actingAs($user)->postJson('/api/projects', ['name' => 'New Project']);
$response->assertCreated();
assertDatabaseHas('projects', ['name' => 'New Project']);
});
Фабрики и состояния 🔧
Используй фабрики с состояниями для граничных случаев:
$user = User::factory()->state(['role' => 'admin'])->create();
Это удобно для ролей (archived, admin, trial).
Фейки для побочных эффектов 🎭
Bus::fake() — для джобов
Queue::fake() — для очередей
Mail::fake() и Notification::fake() — для почты и уведомлений
Event::fake() — для доменных событий
Пример проверки очереди:
Queue::fake();
dispatch(new SendOrderConfirmation($order->id));
Queue::assertPushed(SendOrderConfirmation::class);
Пример проверки уведомления:
Notification::fake();
$user->notify(new InvoiceReady($invoice));
Notification::assertSentTo($user, InvoiceReady::class);
Тестирование аутентификации (Sanctum) 🔐
Sanctum::actingAs($user);
$response = $this->getJson('/api/projects');
$response->assertOk();
Внешние HTTP-сервисы 🌐
Используй Http::fake() и Http::assertSent() для изоляции и проверки исходящих запросов.
Тестирование авторизации ✋
Проверяй политики через Gate:
$this->assertTrue(Gate::forUser($user)->allows('update', $project));
$this->assertFalse(Gate::forUser($otherUser)->allows('update', $project));
Inertia.js тесты 🖼️
Для приложений с Inertia используй хелпер assertInertia, проверяя имя компонента и пропсы:
$response->assertInertia(fn (AssertableInertia $page) =>
$page->component('Dashboard')
->where('user.id', $user->id)
->has('projects')
);
Команды для запуска
php artisan test
vendor/bin/phpunit
vendor/bin/pest
Конфигурация phpunit.xml 🛠️
Настрой DB_CONNECTION=sqlite и DB_DATABASE=:memory: для быстрых тестов. Используй отдельное окружение для тестов, чтобы не затронуть dev/prod данные.
Когда использовать ✅
- Разработка новой фичи или эндпоинта
- Исправление бага или рефакторинг
- Тестирование моделей, политик, джобов и уведомлений
- Интеграция с внешними API
- Inertia-страницы
Важно знать ⚠️
- Цель — 80%+ покрытия (unit + feature)
- Для сбора покрытия используй pcov или
XDEBUG_MODE=coverage в CI
- Предпочитай
assertDatabaseHas вместо ручных запросов к БД
- В Feature-тестах используй
actingAs (Pest) или ActingAs (PHPUnit) для аутентификации
- При наличии транзакций
RefreshDatabase выполняется с минимальными накладными расходами
Комментарии
Комментариев пока нет. Будьте первым.