Тестування Laravel у 2026: Pest, Mocking та питання технічних співбесід
Повний посібник з тестування Laravel-застосунків за допомогою Pest у 2026 році. Розглядаються Feature та Unit тести, мокінг фасадів, архітектурні тести, мутаційне тестування та типові питання технічних співбесід.

Тестування є невід'ємною частиною професійної розробки на Laravel. У 2026 році екосистема PHP досягла нового рівня зрілості, а фреймворк Pest став стандартом де-факто для написання тестів у Laravel-проєктах. Сучасні команди розробників очікують від кандидатів глибокого розуміння тестових практик, адже якість коду безпосередньо впливає на стабільність продукту та швидкість впровадження нових функцій.
Ця стаття охоплює ключові аспекти тестування Laravel-застосунків: від базової конфігурації Pest до просунутих технік мокінгу зовнішніх сервісів. Особлива увага приділяється архітектурним тестам та мутаційному тестуванню — інструментам, які допомагають забезпечити високу якість тестового покриття. Наприкінці наведено типові питання технічних співбесід, що дозволить підготуватися до інтерв'ю на позиції Laravel-розробника.
Матеріал розрахований на розробників із базовим досвідом роботи з Laravel, які прагнуть поглибити свої знання у сфері тестування та підготуватися до технічних співбесід у провідних IT-компаніях.
Pest побудований на основі PHPUnit, але пропонує значно лаконічніший синтаксис завдяки функціональному підходу. Замість створення класів та методів розробники описують тести за допомогою функцій it() та test(). Це скорочує обсяг boilerplate-коду на 40-60% порівняно з класичним PHPUnit. Крім того, Pest надає вбудовану підтримку архітектурних тестів, паралельного виконання та мутаційного тестування — функцій, які потребують додаткових плагінів у PHPUnit.
Налаштування Pest у Laravel-проєкті
Конфігурація Pest виконується через файл tests/Pest.php, де визначаються базові налаштування для різних типів тестів. Трейт RefreshDatabase автоматично скидає базу даних перед кожним Feature-тестом, забезпечуючи ізоляцію тестових сценаріїв.
use Illuminate\Foundation\Testing\RefreshDatabase;
pest()
->extend(Tests\TestCase::class)
->use(RefreshDatabase::class)
->in('Feature');Метод extend() вказує базовий клас для тестів, а use() додає необхідні трейти. Директива in('Feature') обмежує застосування цих налаштувань лише до Feature-тестів, залишаючи Unit-тести максимально швидкими без звернення до бази даних.
Feature-тести: валідація HTTP-ендпоінтів
Feature-тести перевіряють роботу застосунку на рівні HTTP-запитів, імітуючи реальну взаємодію користувачів із системою. Такі тести охоплюють повний цикл обробки запиту: маршрутизацію, валідацію, бізнес-логіку та формування відповіді.
use App\Models\User;
it('registers a new user with valid data', function () {
$response = $this->postJson('/api/register', [
'name' => 'Jane Doe',
'email' => 'jane@example.com',
'password' => 'SecurePass123!',
'password_confirmation' => 'SecurePass123!',
]);
$response->assertStatus(201)
->assertJsonStructure(['user' => ['id', 'name', 'email']]);
expect(User::where('email', 'jane@example.com')->exists())->toBeTrue();
});Тест демонструє комплексну перевірку процесу реєстрації: HTTP-статус відповіді, структуру JSON та фактичне створення запису в базі даних. Функція expect() з бібліотеки Expectation API забезпечує читабельний синтаксис для assertions.
Unit-тести з Pest: ізольована бізнес-логіка
Unit-тести фокусуються на окремих класах та методах, перевіряючи їхню поведінку в ізоляції від решти системи. Блок describe() групує пов'язані тести, створюючи логічну структуру тестового файлу.
use App\Services\PriceCalculator;
describe('PriceCalculator', function () {
it('applies a percentage discount correctly', function () {
$calculator = new PriceCalculator();
// 20% off a 150.00 base price
$result = $calculator->applyDiscount(150.00, 20);
expect($result)->toBe(120.00);
});
it('rejects negative discount values', function () {
$calculator = new PriceCalculator();
expect(fn () => $calculator->applyDiscount(100.00, -5))
->toThrow(InvalidArgumentException::class);
});
});Перший тест перевіряє коректність обчислення знижки, другий — правильну обробку некоректних вхідних даних. Метод toThrow() дозволяє елегантно тестувати винятки без використання анотацій чи блоків try-catch.
Мокінг фасадів Laravel: Mail, Queue, Notifications
Laravel надає вбудовані механізми для мокінгу фасадів, що дозволяє тестувати відправку листів, постановку задач у чергу та надсилання сповіщень без реального виконання цих операцій.
use App\Models\Order;
use App\Models\User;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Queue;
use App\Mail\OrderConfirmation;
use App\Jobs\ProcessPayment;
it('dispatches payment job and sends confirmation email', function () {
// Fake both Mail and Queue facades
Mail::fake();
Queue::fake();
$user = User::factory()->create();
$order = Order::factory()->for($user)->create([
'total' => 99.99,
'status' => 'pending',
]);
// Act: confirm the order via HTTP
$this->actingAs($user)
->postJson("/api/orders/{$order->id}/confirm")
->assertOk();
// Assert: payment job was dispatched with correct amount
Queue::assertPushed(ProcessPayment::class, function ($job) use ($order) {
return $job->order->id === $order->id
&& $job->order->total === 99.99;
});
// Assert: confirmation email was sent to the user
Mail::assertSent(OrderConfirmation::class, function ($mail) use ($user) {
return $mail->hasTo($user->email);
});
});Методи Mail::fake() та Queue::fake() перехоплюють виклики відповідних фасадів, дозволяючи перевірити, які листи мали бути відправлені та які задачі поставлені в чергу. Callback-функції в методах assertPushed() та assertSent() забезпечують детальну перевірку параметрів.
Готовий до співбесід з Laravel?
Практикуйся з нашими інтерактивними симуляторами, flashcards та технічними тестами.
Просунутий мокінг з Mockery: зовнішні сервіси
Для мокінгу власних сервісів та зовнішніх API використовується бібліотека Mockery, яка інтегрована в Pest. Мок-об'єкти дозволяють контролювати поведінку залежностей та перевіряти правильність їхнього виклику.
use App\Services\PaymentGateway;
use App\Services\StripeClient;
it('charges the customer through the payment gateway', function () {
// Create a mock of the Stripe client
$stripeClient = Mockery::mock(StripeClient::class);
$stripeClient->shouldReceive('charge')
->once()
->with('cus_abc123', 5000, 'usd')
->andReturn(['status' => 'succeeded', 'id' => 'ch_xyz']);
// Bind the mock in the container
$this->app->instance(StripeClient::class, $stripeClient);
$gateway = app(PaymentGateway::class);
$result = $gateway->processCharge('cus_abc123', 50.00);
expect($result['status'])->toBe('succeeded');
});Мок StripeClient визначає очікуваний виклик методу charge() з конкретними параметрами. Директива once() гарантує, що метод буде викликано рівно один раз. Прив'язка мока до сервіс-контейнера через $this->app->instance() забезпечує його використання замість реального класу.
Архітектурні тести: забезпечення конвенцій проєкту
Архітектурні тести Pest дозволяють автоматизувати перевірку дотримання архітектурних правил проєкту. Це особливо корисно для великих команд, де важливо підтримувати єдині стандарти кодування.
arch('controllers do not use Eloquent directly')
->expect('App\Http\Controllers')
->not->toUse('Illuminate\Database\Eloquent');
arch('services are final classes')
->expect('App\Services')
->toBeFinal();
arch('no debugging functions in production code')
->expect(['dd', 'dump', 'var_dump', 'ray'])
->not->toBeUsed();Перший тест забороняє контролерам використовувати Eloquent напряму, примушуючи працювати через сервісний шар. Другий вимагає, щоб усі сервіси були final-класами. Третій запобігає потраплянню debug-функцій у production-код.
Pest також надає готові пресети для типових архітектурних перевірок:
arch()->preset()->laravel();
arch()->preset()->security();
arch()->preset()->php();Пресет laravel() включає перевірки специфічні для Laravel-застосунків, security() — перевірки безпеки, php() — загальні best practices PHP.
Мутаційне тестування: оцінка реальної якості тестів
Мутаційне тестування вносить невеликі зміни (мутації) у production-код та перевіряє, чи тести виявляють ці зміни. Високий відсоток виявлених мутацій свідчить про якісні тести, тоді як низький — про поверхневе покриття.
# Run mutation testing on a specific class
php artisan test --mutate --class=App\\Services\\PriceCalculatorРозглянемо різницю між тестом з високим покриттям, але низьким mutation score, та якісним тестом:
// Example: this test has high coverage but low mutation score
it('calculates shipping cost', function () {
$cost = calculateShipping(weight: 5.0, zone: 'domestic');
// Only checks that the result is numeric
expect($cost)->toBeFloat();
});
// Improved: catches mutations by asserting the exact value
it('calculates domestic shipping for 5kg package', function () {
$cost = calculateShipping(weight: 5.0, zone: 'domestic');
// Exact assertion catches operator and value mutations
expect($cost)->toBe(12.50);
});Перший тест лише перевіряє тип результату — мутатор може змінити формулу обчислення, і тест все одно пройде. Другий тест перевіряє конкретне значення, тому будь-яка мутація буде виявлена.
Комплексні тестові сценарії для співбесід
На технічних співбесідах часто просять написати тести для типових бізнес-сценаріїв. Розглянемо приклад тестування публікації статті:
use App\Models\Article;
use App\Models\User;
it('publishes a draft article and updates the timestamp', function () {
$author = User::factory()->create(['role' => 'editor']);
$article = Article::factory()
->for($author, 'author')
->draft()
->create(['title' => 'Testing Best Practices']);
$this->actingAs($author)
->patchJson("/api/articles/{$article->id}/publish")
->assertOk()
->assertJsonPath('data.status', 'published');
$article->refresh();
expect($article->status)->toBe('published')
->and($article->published_at)->not->toBeNull()
->and($article->published_at->isToday())->toBeTrue();
});Тест демонструє використання factory-станів (draft()), зв'язків між моделями (for()), HTTP-тестування та ланцюжкових assertions. Метод refresh() оновлює модель з бази даних для перевірки змін.
Комплексне тестування API-автентифікації:
use App\Models\User;
describe('API Authentication', function () {
it('rejects unauthenticated requests with 401', function () {
$this->getJson('/api/profile')
->assertUnauthorized();
});
it('returns the authenticated user profile', function () {
$user = User::factory()->create([
'name' => 'John Doe',
'email' => 'john@example.com',
]);
$this->actingAs($user)
->getJson('/api/profile')
->assertOk()
->assertJson([
'data' => [
'name' => 'John Doe',
'email' => 'john@example.com',
],
]);
});
it('validates required fields on registration', function () {
$this->postJson('/api/register', [])
->assertUnprocessable()
->assertJsonValidationErrors(['name', 'email', 'password']);
});
});Цей набір тестів охоплює три ключові аспекти автентифікації: захист ендпоінтів від неавторизованого доступу, коректну роботу з авторизованим користувачем та валідацію вхідних даних.
Починай практикувати!
Перевір свої знання з нашими симуляторами співбесід та технічними тестами.
Питання технічних співбесід з тестування Laravel
Нижче наведено типові питання, які задають на співбесідах для Laravel-розробників:
Базовий рівень:
- Яка різниця між Feature та Unit тестами в Laravel?
- Як працює трейт RefreshDatabase і коли його використовувати?
- Поясніть призначення методу actingAs() у тестах.
- Чим відрізняється assertJson() від assertExactJson()?
Середній рівень:
- Як тестувати відправку email без реального надсилання листів?
- Поясніть різницю між Mail::fake() та Mail::assertSent().
- Як мокати зовнішні HTTP-запити в тестах?
- Що таке database factories і як використовувати стани?
Просунутий рівень:
- Як організувати тестування мікросервісної архітектури?
- Поясніть концепцію мутаційного тестування та його переваги.
- Як архітектурні тести Pest допомагають підтримувати якість коду?
- Опишіть стратегію тестування event-driven систем у Laravel.
Практичні завдання:
- Напишіть тест для ендпоінта оновлення профілю користувача з валідацією.
- Створіть тест для job, який обробляє платіж та надсилає сповіщення.
- Напишіть архітектурний тест, що забороняє використання env() у сервісах.
Висновок
Тестування Laravel-застосунків у 2026 році вимагає володіння широким набором інструментів та технік. Pest значно спрощує написання тестів завдяки лаконічному синтаксису, а вбудована підтримка архітектурних тестів та мутаційного тестування дозволяє забезпечити високу якість кодової бази.
Для успішного проходження технічних співбесід важливо не лише знати теорію, але й мати практичний досвід написання різних типів тестів. Рекомендується регулярно практикуватися на реальних проєктах, впроваджувати TDD-підхід та аналізувати mutation score для виявлення слабких місць у тестовому покритті.
Постійне вдосконалення навичок тестування є ключовим фактором професійного зростання Laravel-розробника. Якісні тести не лише запобігають регресіям, але й слугують документацією до коду, полегшуючи онбординг нових членів команди та підтримку проєкту в довгостроковій перспективі.
Теги
Поділитися
Пов'язані статті

Laravel 12 у 2026 році: нові можливості, Starter Kits та питання для співбесіди
Повний огляд Laravel 12: перероблені Starter Kits на основі React 19, Vue 3, Svelte 5 та Livewire 4, інтеграція WorkOS AuthKit, оновлення залежностей до Carbon 3 та PHP 8.2+, покроковий посібник з оновлення з Laravel 11 та актуальні питання для технічних співбесід у 2026 році.

25 запитань на співбесіді з Laravel та PHP у 2026 році
25 найпоширеніших запитань на співбесіді з Laravel: Service Container, Eloquent ORM, middleware, черги, безпека, тестування та архітектурні патерни з прикладами коду.

Laravel Middleware: Поглиблений огляд автентифікації, Rate Limiting та власних middleware
Вичерпний посібник з middleware у Laravel — від автентифікації та rate limiting до створення власних класів middleware. Практичні приклади коду та патерни для продакшену.