ru:https://highload.today/blogs/testiruem-veb-prilozheniya-s-pomoshhyu-laravel-i-phpunit-kak-pravilno-pisat-testy-s-primerami/ ua:https://highload.today/uk/blogs/testuyemo-vebdodatki-za-dopomogoyu-laravel-ta-phpunit-yak-pravilno-pisati-testi-z-prikladami/
logo
Тестування      02/11/2022

Тестуємо вебдодатки за допомогою Laravel та PHPUnit: як правильно писати тести — з прикладами

Ігор Куницький BLOG

Senior PHP developer у Binariks

Всім привіт, мене звати Ігор, я PHP-розробник у компанії Binariks. У цій статті я розповім вам про можливості тестування, які надає фреймворк Laravel в поєднанні з PHPUnit, тому запарюйте чайок та готуйтесь до лонгріду 🙂

Наявність валідних тестів з хорошим покриттям — одне з правил якісного коду. З їх допомогою можна швидко виявити проблеми в функціоналі, відповідно й прискорити вихід функціонала в прод. Вони спрощують життя QA-команді, зменшуючи кількість однотипного мануального тестування, тим самим зменшуючи вплив людського фактора.

В залежності від ступеня ізоляції тести розділяють на наступні типи:

  • Unit Tests: максимально ізольовані тести. Використовуються для тестування окремого методу чи функції. Будь-які зовнішні залежності ізолюються на рівні методу чи функції.
  • Components/Service Tests: тести, які перевіряють роботу та взаємодію окремих компонентів, чи сервісів. Ізолюються в межах тестованого функціоналу.
  • API/HTTP Tests: тести, що перевіряють те, як працюють окремі АРІ та роботу всіх компонентів, що викликаються при виконанні запиту.
  • Gui Tests: перевіряють роботу, фронтенд- і бекенд-частини в комплексі.

Як слід проводити тести

Перед тим, як почати розповідь про можливості фреймворку, думаю, варто нагадати правила хороших тестів:

  • Тести мають бути швидкими.
  • Варто уникати надлишкової абстракції в тестах. Код повинен бути читабельним і зрозумілим без надлишкового копання.
  • Онлайн-курс "Проджект-менеджер в ІТ" від Laba.
    Навчіться запускати, контролювати й успішно реалізовувати ІТ-проєкти. Пройти весь шлях проєктного управління на реальному кейсі вам допоможе PMD із 19-річним досвідом в ІТ.
    Детальніше про курс
  • Назви тестів повинні бути читабельними.
  • Test-Driven Development (TDD) — це методологія, коли тести пишуться перед імплементуванням певного функціоналу. Переваги цього підходу в тому, що ви відразу будете писати майбутній код таким чином, щоб його можна було легко тестувати. Також ця методологія зменшує кількість регресивних тестів (тести, що покривають функціонал після його імплементації).
  • Підготуй, проведи, перевір.

Хороший тест має три стадії:

  • підготовка — генерування вхідних даних та станів системи;
  • проведення тесту — проведення дій, потрібних для тесту;
  • перевірка — проведення дій для перевірки вихідних даних та станів системи.

  • Тест повинен бути відтворюваним і повертати однаковий результат незалежно від кількості викликів.
  • Онлайн-курс "Створення електронної музики" від Skvot.
    Практичний курс про те, як знайти власний стиль та написати й зарелізити свій перший трек.
    Програма курсу і реєстрація
  • Тести не повинні залежати один від одного. Якщо в одного тесту буде залежність від іншого, він може повернути помилку в разі окремого виклику.
  • Тест має перевіряти тільки один конкретний тестовий сценарій.
  • Вхідні дані тестів повинні бути реалістичними (використовувати фейкери, для генерування тестових даних — хороша практика).
  • Якщо для тестування потрібно використовувати базу даних — створіть окрему, на якій ви будете проводити тести.
  • Уникайте логічних виразів в тестах. На зображенні нижче покажу приклади того, як НЕ ВАРТО РОБИТИ:

  • Всі зовнішні залежності в тесті повинні бути ізольованими.
  • Завжди перевіряйте дані відповідними методами. Перевірка даних повинна відбуватися не тільки за значенням, але й за типом.
  • Для максимальної користі з тестів інтегруйте ваші тести в CI/CD — це допоможе вам уникнути людського фактора, який завжди присутній в розробці.
  • Онлайн-курс "Створення особистого бренду" від Skvot.
    Прокачайте особистий бренд для підсилення власного бізнесу, підвищення продажів та впізнаваність на ринку.
    Дізнатись більше про програму курсу і досвід лектора
  • Покриття тестами має бути максимально можливим. Пишіть тести для різних сценаріїв. Ідеально, коли всі можливі варіанти роботи функціонала покриті тестами. Хорошим показником вважається, коли хоча б 70-80% функціоналу покрито тестами.
  • Крім всього вище переліченого, тести можуть слугувати прикладами того, як працює функціонал, що тестується. Тому добре розглядати тести як частину специфікації чи документації.

Особливості тестування в Laravel за допомогою PHPUnit

Підтримка тестування за допомогою PHPUnit включена «з коробки», а файл phpunit.xml уже налаштовано для вашої програми. Також у фреймворк додано багато допоміжних методів, які є зручними й спрощують тестування.

За замовчуванням каталог tests в Laravel містить дві папки Feature і Unit.

Unit

Юніт-тести призначені для тестування маленької ізольованої частини вашого коду. Окремого методу класу чи функції.

Тести в директорії Unit не ініціюють ваш Laravel-додаток, тому з юніт-тестами ви не зможете отримати доступ до сервісів Laravel чи бази даних.

Наведу приклад написання юніт-тестів з практичним застосуванням вищеперелічених правил.

Завдання: імплементувати метод getSubscription в класі SubscriptionService, який буде пропонувати користувачеві підписки в залежності від типу його акаунту:

  • якщо користувач має преміум-акаунт — пропонувати йому преміум-підписки;
  • Онлайн-курс "Режисура та візуальний сторітелінг" від Skvot.
    Перетворюй свої ідеї на сильні історії в рекламі, кліпах чи кіно Досвідом ділиться режисер, продюсер та власник продакшену, який 10+ років у професії.
    Детальніше про курс
  • якщо у користувача звичайний акаунт — пропонувати йому базові підписки.

Відповідно до методології TDD почнемо з написання тестів і описуємо очікувану поведінку метода:

Створюємо сам функціонал:

Викликаємо тести:

Юніт-тести корисні для перевірки роботи окремих важливих частин коду. Вони швидкі і пишуться відносно просто, дають високу стабільність коду, що покритий тестами.

Проте їх ізольованість має і недоліки, а саме — вони не можуть гарантувати коректну взаємодію всіх окремо протестованих частин коду, при реальних сценаріях, коли код не є ізольованим.

Онлайн-курс "Фінансовий директор" від Laba.
Опануйте інструменти управління грошовими потоками, ризиками та активами компанії, щоби перейти на посаду CFO.
Приєднатися до курсу

Feature

На відміну від директорії Unit, тести в каталозі Feature призначені для тестування взаємодії різних компонентів програми. Вони ініціюють ваш Laravel-додаток.

Відповідно, з допомогою цих тестів можна перевіряти більшу частину вашого коду, починаючи від окремих методів, які працюють в інфраструктурі Laravel, те, як кілька об’єктів взаємодіють один з одним або навіть повний запит HTTP включно з відповіддю з сервера.

Згідно з рекомендаціями розробників фреймворку Laravel, більшість ваших тестів мають бути Feature-тестами. Тому що ці типи тестів забезпечують більшу впевненість у тому, що ваша система функціонує належним чином.

Написання Feature-тестів має кілька особливостей:

  • Оскільки тести мають доступ до бази даних, для тестування варто створити окрему базу даних, на якій будуть генеруватися і тестуватися дані.
  • Файл PHPunit.xml дозволить задати чи перезаписати всі .env-змінні (в тому числі і конфігурації, які відповідають). Крім того, ви можете створити файл .env.testing — в такому випадку він буде використовуватися замість .env-файлу при тестуванні.
  • Для оновлення даних Laravel пропонує трейт Illuminate\ Foundation\ Testing\ RefreshDatabase, який здійснює всі міграції та ініціює транзакцію, яка поверне вашу базу даних до вихідного стану після завершення тесту.
  • Для генерування тестових даних варто використовувати Faker, Factories, Seeders.
  • При тестуванні HTTP-запитів варто використовувати функціонал Named Routes — це простий і зручний спосіб генерування складних URL.
  • Воркшоп "PR + AI: Рисерч, Креатив, Контент" від Skvot.
    Навчіться адаптувати потенціал АІ під задачі піарника. Корисні тулзи, яким можна делегувати рутину, генерувати свіжі ідеї для контенту і піар-стратегій.
    Дізнатись більше
  • Використовуйте Laravel Mocks для логінів, завантаження файлів, Events тощо.

Тестування компонента. Приклад: в модель User потрібно додати scope, який буде фільтрувати записи в базі даних за полем is_admin:

  • якщо в scope буде передаватися true — повертати всі записи, в яких поле is_admin true;
  • якщо в scope буде передаватися false — повертати всі записи, в яких поле is_admin false.

Напишемо тест:

Додамо відповідний scope в модель User:

Переконаємося, що тест працює коректно:

Курс Project Manager від Powercode academy.
Онлайн-курс Project Manager. З нуля за 3,5 місяці до нової позиції Без знання коду, англійської та стресу.
Зарееструватися

Додамо тест для другого випадку:

Перевіримо обидва випадки:

Тестування АРІ. Приклад:

  • написати тест, який буде перевіряти наступний функціонал;
  • створити endpoint POST: api/articles;
  • цей endpoint повинен зберігати в базу даних (user_id (id залогованого користувача), title, text);
  • Курс Python від Mate academy.
    Python дозволяє тобі не тільки розробляти сайти та займатись аналітикою даних, а ще й будувати алгоритми, тестувати програми та навіть створювати штучні інтелекти. Стань різноплановим фахівцем!
    Реєстрація на курс
  • доступ до endpoint може мати тільки користувач з правами admin (users.is_admin === true);
  • при успішному виконанні відповідь з сервера статус 200, та наступні поля.
{
    “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() — надають можливість перевірки статус відповіді з сервера та його структури;
  • Онлайн-курс "Арт Менеджер" від Skvot.
    Навчіться шукати фінансування та планувати бюджет, керувати командою, запускати артпроєкти та пітчити їх так, щоб великі компанії захотіли колабитися.
    Детальніше про курс
  • view(), blade() — можливість перевірки згенерованих фреймворком сторінок.

2) Методи для імітації роботи функціонала:

  • у фреймворку передбачена можливість імітування черг, завантажень файлів, нотифікацій, передачі в контейнер імітації роботи певного об’єкта, роботи з часом.

3) Тестування бази даних:

  • контроль за міграціями, можливість скасовувати зміни в базі даних після закінчення тесту, методи для тестування наявності (чи відсутності) певних даних в базі даних.

4) Методи для тестування консолі:

  • фреймворк надає можливості з тестування вхідних та вихідних даних артісанівської консолі;
  • з встановленням пекеджу Dusk з’являється можливість імітування роботи браузерів і написання GUI-тестів.

В цій статті я намагався коротко описати загальні хороші практики, які варто використовувати при написанні тестів, та показати приклади різних типів тестів, та їх імплементації в середовищі Laravel, зробити короткий огляд можливостей тестування в середовищі фреймворка.

Онлайн-курс "Фінансовий аналіз" від Laba.
Навчіться читати фінзвітність так, щоб ухвалювати ефективні бізнес-рішення.Досвідом поділиться експерт, що 20 років займається фінансами і їхньою автоматизацією.
Детальніше про курс

Сподіваюся, ця стаття буде вам корисною. Всім успіхів!

Читайте також: Як написати односторінковий додаток на Laravel та Vue.js за 45 хвилин

Якщо ви знайшли помилку, будь ласка, виділіть фрагмент тексту та натисніть Ctrl+Enter.

Онлайн-курс "Excel та Power BI для аналізу даних" від robot_dreams.
Навчіться самостійно аналізувати й візуалізувати дані, знаходити зв’язки, розуміти кожен аспект отриманої інформації та перетворювати її на ефективні рішення.
Детальніше про курс

Цей матеріал – не редакційний, це – особиста думка його автора. Редакція може не поділяти цю думку.

Топ-5 найпопулярніших блогерів березня

PHP Developer в ScrumLaunch
Всего просмотровВсього переглядів
2434
#1
Всего просмотровВсього переглядів
2434
Founder at Shallwe, Python Software Engineer (Django/React)
Всего просмотровВсього переглядів
113
#2
Всего просмотровВсього переглядів
113
Career Consultant в GoIT
Всего просмотровВсього переглядів
95
#3
Всего просмотровВсього переглядів
95
CEO & Founder в Trustee
Всего просмотровВсього переглядів
94
#4
Всего просмотровВсього переглядів
94
Рейтинг блогерів

Найбільш обговорювані статті

Топ текстів

Ваша жалоба отправлена модератору

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: