Знайдіть функціональні тести, які створюють записи в базі даних без звичайного оновлення бази даних у Laravel

Перекладено ШІ
Оригінал: Laravel News
Оновлено: 04 жовтня, 2025
При тестуванні функцій Laravel вам пропонуються ефективні інструменти для тестування бази даних, такі як trait `RefreshDatabase`. Чи знаєте ви, що забуття цього trait може викликати дивні помилки у тестах? Дізнайтеся, як уникнути цих проблем та зробити ваші тести більш надійними!

При тестуванні функцій у Laravel ви можете скористатися корисними інструментами для роботи з базами даних, такими як оновлення бази, фабрики, сидери та асерції. У сучасному Laravel-тесті на Pest, що використовує оновлення бази даних, код може виглядати так:

use Illuminate\Foundation\Testing\RefreshDatabase;

pest()->use(RefreshDatabase::class);

test('basic example', function () {
    $user = User::factory()->create();
    $response = $this->actingAs($user)->get('/');

    // ...
});

На жаль, розробники іноді можуть забувати додавати трейт RefreshDatabase, що призводить до випадкових помилок в інших тестах. Щоб уникнути цього, можна додати трейт до всіх функціональних тестів. У файлі tests/Pest.php розкоментуйте цю строку:

pest()->extend(Tests\TestCase::class)
    ->use(Illuminate\Foundation\Testing\RefreshDatabase::class)
    ->in('Feature');

Документація Laravel говорить про трейт RefreshDatabase так:

Трейт Illuminate\Foundation\Testing\RefreshDatabase не виконує міграцію бази даних, якщо ваша схема актуальна. Він лише виконує тест у межах транзакції бази даних. Отже, записи, додані тестами, що не використовують цей трейт, можуть залишитися в базі даних.

Таким чином, тести без цього трейту не працюватимуть у відкоті транзакцій, що може викликати дивні помилки в асерціях вашого додатку. Один із способів швидше знайти проблемні тести — використовувати grep для пошуку файлів, які не використовують RefreshDatabase, але містять виклики factory(), seed() тощо:

grep -rL 'RefreshDatabase' tests/Feature | xargs grep -l '::factory('

Ця команда відобразить файли, в яких немає трейту RefreshDatabase, але є виклики ::factory(). Якщо в нашому прикладі тесту ми видалимо трейт і виконаємо цю команду:

$ grep -rL 'RefreshDatabase' tests/Feature | xargs grep -l '::factory('

tests/Feature/ExampleTest.php

Слід зазначити, що тест без викликів ::factory() може все ще створювати записи через сидери або HTTP-запити. Ви можете просто запустити першу частину команди для більш уважного розслідування, скористатися AI або ще більше відфільтрувати. Використання першої частини початкової команди також покаже наш приклад файлу. Зазвичай цього достатньо для подальшого розслідування інших файлів:

$ grep -rL 'RefreshDatabase' tests/Feature

tests/Feature/ExampleTest.php

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

grep -rL 'RefreshDatabase' tests/Feature \
  | xargs grep -El '::factory\(|->seed\(|->putJson\(|->postJson\(|->post\(|->put\('

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

Ви навіть можете перетворити це на GitHub workflow, який не пройде, якщо буде знайдено будь-які файли, що підпадають під вищезазначений пошук. Ваші результати можуть варіюватись, але ось уявний (не тестований) варіант GitHub workflow, який перевіряє, чи є файли, що відповідають цим умовам:

name: Check for Missing RefreshDatabase

on:
  pull_request:
    paths:
      - 'tests/Feature/**'

jobs:
  check-refresh-database:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Find files missing RefreshDatabase that use database features
        run: |
          set -e
          files=$(grep -rL 'RefreshDatabase' tests/Feature | xargs grep -El '::factory\(|->seed\(|->putJson\(|->postJson\(|->post\(|->put\(' || true)
          if [ -n "$files" ]; then
            echo "The following files are missing 'RefreshDatabase':"
            echo "$files"
            exit 1
          fi

Ще один нюанс: записи бази даних можуть бути вставлені через моделі! Як я вже згадував, цей grep пошук не ідеальний; це інструмент, що допоможе швидше знайти файл, який вставляє записи в базу даних без міграцій.

Рекомендую дотримуватись таких конвенцій:

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