Всім привіт, мене звати Ігор, я PHP-розробник у компанії Binariks. У цій статті я розповім вам про можливості тестування, які надає фреймворк Laravel в поєднанні з PHPUnit, тому запарюйте чайок та готуйтесь до лонгріду 🙂
Наявність валідних тестів з хорошим покриттям — одне з правил якісного коду. З їх допомогою можна швидко виявити проблеми в функціоналі, відповідно й прискорити вихід функціонала в прод. Вони спрощують життя QA-команді, зменшуючи кількість однотипного мануального тестування, тим самим зменшуючи вплив людського фактора.
В залежності від ступеня ізоляції тести розділяють на наступні типи:
Перед тим, як почати розповідь про можливості фреймворку, думаю, варто нагадати правила хороших тестів:
Хороший тест має три стадії:
Підтримка тестування за допомогою PHPUnit включена «з коробки», а файл phpunit.xml уже налаштовано для вашої програми. Також у фреймворк додано багато допоміжних методів, які є зручними й спрощують тестування.
За замовчуванням каталог tests в Laravel містить дві папки Feature і Unit.
Юніт-тести призначені для тестування маленької ізольованої частини вашого коду. Окремого методу класу чи функції.
Тести в директорії Unit не ініціюють ваш Laravel-додаток, тому з юніт-тестами ви не зможете отримати доступ до сервісів Laravel чи бази даних.
Наведу приклад написання юніт-тестів з практичним застосуванням вищеперелічених правил.
Завдання: імплементувати метод getSubscription в класі SubscriptionService, який буде пропонувати користувачеві підписки в залежності від типу його акаунту:
Відповідно до методології TDD почнемо з написання тестів і описуємо очікувану поведінку метода:
Створюємо сам функціонал:
Викликаємо тести:
Юніт-тести корисні для перевірки роботи окремих важливих частин коду. Вони швидкі і пишуться відносно просто, дають високу стабільність коду, що покритий тестами.
Проте їх ізольованість має і недоліки, а саме — вони не можуть гарантувати коректну взаємодію всіх окремо протестованих частин коду, при реальних сценаріях, коли код не є ізольованим.
На відміну від директорії Unit, тести в каталозі Feature призначені для тестування взаємодії різних компонентів програми. Вони ініціюють ваш Laravel-додаток.
Відповідно, з допомогою цих тестів можна перевіряти більшу частину вашого коду, починаючи від окремих методів, які працюють в інфраструктурі Laravel, те, як кілька об’єктів взаємодіють один з одним або навіть повний запит HTTP включно з відповіддю з сервера.
Згідно з рекомендаціями розробників фреймворку Laravel, більшість ваших тестів мають бути Feature-тестами. Тому що ці типи тестів забезпечують більшу впевненість у тому, що ваша система функціонує належним чином.
Написання Feature-тестів має кілька особливостей:
PHPunit.xml дозволить задати чи перезаписати всі .env-змінні (в тому числі і конфігурації, які відповідають). Крім того, ви можете створити файл .env.testing — в такому випадку він буде використовуватися замість .env-файлу при тестуванні.Illuminate\ Foundation\ Testing\ RefreshDatabase, який здійснює всі міграції та ініціює транзакцію, яка поверне вашу базу даних до вихідного стану після завершення тесту.Тестування компонента. Приклад: в модель User потрібно додати scope, який буде фільтрувати записи в базі даних за полем is_admin:
scope буде передаватися true — повертати всі записи, в яких поле is_admin true;scope буде передаватися false — повертати всі записи, в яких поле is_admin false.Напишемо тест:
Додамо відповідний scope в модель User:
Переконаємося, що тест працює коректно:
Додамо тест для другого випадку:
Перевіримо обидва випадки:
Тестування АРІ. Приклад:
user_id (id залогованого користувача), title, text);users.is_admin === true);{
“user_id”: (id користувача),
“id”: (article id),
“title”: (поле title)
}
<?php
namespace Tests\Feature;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;
class CreateArticleTest extends TestCase
{
use RefreshDatabase;
use WithFaker;
public function setUp(): void
{
parent::setUp();
// виключаємо з тесту всі мідлвер, що не відносяться до тесту
$this->withoutMiddleware();
}
public function testCreateArticleSuccess()
{
// Створюємо користувача-адміна
$user = User::factory()->create([
'is_admin' => true,
]);
// З допомогою фейкера генеруємо дані запиту
$request = [
'title' => $this->faker()->text(6),
'text' => $this->faker()->text(50),
];
// З допомогою методу actingAs() імітуємо поведінку запиту для адміна
$response = $this->actingAs($user)
// виконуємо сам запит
->post(
// перший параметр - роут згенерований з допомогою Laravel функціоналу Named routes
route('articles.create'),
// Другий параметр - request body
$request,
);
// Перевірка результату:
// Перевіряємо, чи відповідь з сервера 200
$response->assertStatus(200)
// Перевірка структури відповіді
->assertJsonStructure([
'id',
'user_id',
'title',
])
// перевірка достовірності отриманих даних
->assertJson([
'user_id' => $user->id,
'title' => $request['title'],
])
// Конвертуємо відповідь в array, щоб отримати id статті
->json();
// Перевіряємо, чи був створений запис в базі даних
$this->assertDatabaseHas('articles', [
'id' => $response['id'],
'user_id' => $response['user_id'],
'title' => $response['title'],
'text' => $request['text'],
]);
}
}
Laravel «з коробки» має багато методів, що будуть корисні при тестуванні. Коротко пройдуся по них і додам корисні посилання (на документацію 🙂 ):
1) HTTP-тести. Назва каже сама за себе — їх мета провести тестування конкретних ендпойнтів сервера. Часто при тестуванні доводиться стикатися з наступними методами фреймворку:
withoutMiddleware() — допомагає відключити всі чи задані Middleware;withHeaders(), withSession(), withCookies() — імітують наявність в запиті певних хедерів, сесій, кукі;actingAs() — імітує поведінку сервера при певному авторизованому користувачеві;get(), post(), put(), patch(), delete(), json() — імітує відповідні методи виклику севера;assertStatus(), assertJson(), assertJsonStructure() — надають можливість перевірки статус відповіді з сервера та його структури;view(), blade() — можливість перевірки згенерованих фреймворком сторінок.2) Методи для імітації роботи функціонала:
4) Методи для тестування консолі:
В цій статті я намагався коротко описати загальні хороші практики, які варто використовувати при написанні тестів, та показати приклади різних типів тестів, та їх імплементації в середовищі Laravel, зробити короткий огляд можливостей тестування в середовищі фреймворка.
Сподіваюся, ця стаття буде вам корисною. Всім успіхів!
Читайте також: Як написати односторінковий додаток на Laravel та Vue.js за 45 хвилин
За останні десять років криптоіндустрія пройшла шлях від експериментальної ніші до одного з ключових сегментів…
Щосекундно збільшується обсяг інформації в мережі. Бізнес збирає дорогоцінні байти даних, структурує їх, аналізує і…
Штучний інтелект (ШІ) вже не просто модне слово, а рушійна сила, що змінює саму суть…
Алгоритм консенсусу – це серце будь-якого блокчейна. Саме він визначає, хто і як записує нові…
Зайшов на сторінку, а там — спінери, skeleton і порожнеча? Це не баг, це —…
Таке запитання мені поставив мій знайомий, коли побачив мій профіль. Я настільки над цим задумалась,…