UA RU
logo
Тестування      02/11/2022

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

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

Senior PHP developer у Binariks

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

Курс QA Manual (Тестування ПЗ мануальне) від Powercode academy.
Навчіться знаходити помилки та контролювати якість сайтів та додатків.
Записатися на курс

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

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

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

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

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

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

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

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

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

  • Всі зовнішні залежності в тесті повинні бути ізольованими.
  • Завжди перевіряйте дані відповідними методами. Перевірка даних повинна відбуватися не тільки за значенням, але й за типом.
  • Для максимальної користі з тестів інтегруйте ваші тести в CI/CD — це допоможе вам уникнути людського фактора, який завжди присутній в розробці.
  • Онлайн-курс “Product Management for AI & ML” від Laba.
    Опануйте практичні інструменти продакт-менеджера в галузі Штучного Інтелекту та Машинного Навчання англійською мовою. Досвід і фідбек від викладача, який 20+ років у галузі технологій. .
    Детальніше
  • Покриття тестами має бути максимально можливим. Пишіть тести для різних сценаріїв. Ідеально, коли всі можливі варіанти роботи функціонала покриті тестами. Хорошим показником вважається, коли хоча б 70-80% функціоналу покрито тестами.
  • Крім всього вище переліченого, тести можуть слугувати прикладами того, як працює функціонал, що тестується. Тому добре розглядати тести як частину специфікації чи документації.

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

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

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

Unit

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

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

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

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

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

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

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

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

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

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

Онлайн-курс "Сучасне мистецтво" від Skvot.
За 15 занять розробиш концепт і стратегію для своєї виставки, створиш CV, портфоліо, кураторський путівник, креативну мапу і зможеш стартувати в артсфері — як художник, артменеджер або куратор.
Детальніше

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.
  • Курс Java developer від Mate academy.
    Вивчайте Java та отримайте можливість працювати майже в будь-якій галузі: її використовують від фінансової сфери до аграрної. Працевлаштування гарантуємо!
    Отримати знижку на курс
  • Використовуйте Laravel Mocks для логінів, завантаження файлів, Events тощо.

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

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

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

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

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

Онлайн-курс "Business English для проджект-менеджерів" від Vocabulaba.
Підсилите англійську для управління іноземними командами та вільної комунікації на співбесідах, презентаціях і зідзвонах. .
Детальніше про курс

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

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

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

  • написати тест, який буде перевіряти наступний функціонал;
  • створити endpoint POST: api/articles;
  • цей endpoint повинен зберігати в базу даних (user_id (id залогованого користувача), title, text);
  • Курс QA engineer від Mate academy.
    Після навчання на курсі QA engineer ви зможете розробляти плани тестування додатків та сайтів. Працевлаштування гарантовано.
    Отримати знижку на курс
  • доступ до 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() — надають можливість перевірки статус відповіді з сервера та його структури;
  • Онлайн-курс Бізнес-аналіз. Basic Level від Hillel IT School.
    В ході курсу студенти навчаться техніці збору і аналізу вимог, документуванню та управлінню документацією, управлінню ризиками та змінами, а також навчаться моделювати процеси і прототипуванню.
    Приєднатися
  • view(), blade() — можливість перевірки згенерованих фреймворком сторінок.

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

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

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

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

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

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

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

Основи Python для школярів від Hillel IT School.
Відкрийте для вашої дитини захопливий світ програмування з нашим онлайн-курсом "Програмування Python для школярів". Ми вивчимо основи програмування на прикладі мови Python, надаючи зрозумілі пояснення та цікаві практичні завдання.
Зареєструватися

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

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

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

Основи Web дизайну від Hillel IT School.
Цей онлайн-курс з основ веб-дизайну дозволить вам опанувати мистецтво створення ефективних та привабливих інтерфейсів для вебсайтів і застосунків. Ви оволодієте ключовими принципами UX/UI дизайну, створюватимете дизайн-макети та прототипи, розроблятимете адаптивні інтерфейси для різних пристроїв, готуючись до професійної кар'єри в галузі веб-дизайну.
Дізнатися більше

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

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

Всего просмотровВсього переглядів
35
#1
Всего просмотровВсього переглядів
35
Всего просмотровВсього переглядів
27
#2
Всего просмотровВсього переглядів
27
Всего просмотровВсього переглядів
22
#3
Всего просмотровВсього переглядів
22
Career Consultant в GoIT
Всего просмотровВсього переглядів
21
#4
Всего просмотровВсього переглядів
21
Всего просмотровВсього переглядів
18
#5
Всего просмотровВсього переглядів
18
Рейтинг блогерів
Онлайн-курс “HR Business Partner” від Laba.
Підсилите звʼязок HR- та бізнес-процесів за допомогою вдосконалення аналітичних навичок. Навчіться розробляти HR-стратегії та планувати бюджети відповідно до цілей компанії. .
Детальніше про курс

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

Топ текстів

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

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

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