Типы тестов в Laravel

от автора

Привет, Хабр!

Laravel — это целая экосистема, которая позволяет разрабатывать качественные веб-приложения. Но вот вопрос: как быть уверенным, что все эти красивые строки кода не развалятся в самый неподходящий момент? Ответ очевиден — тесты!

Какие тесты бывают в Laravel

Laravel поддерживает три главных типа тестов: юнит-тесты, интеграционные тесты и функциональные тесты. Каждому своё, каждый важен.

Юнит-тесты

Юнит-тесты — маленькие тесты для маленьких частей кода: методов, функций, классов. Они изолированы от всего остального — ни базы данных, ни API не трогаем, только чистая логика.

Пример? Пожалуйста:

namespace Tests\Unit;  use PHPUnit\Framework\TestCase; use App\Services\DiscountService;  class DiscountServiceTest extends TestCase {     public function test_calculate_discount()     {         $price = 100;         $expectedDiscount = 90; // 10% скидки          $service = new DiscountService();         $actualDiscount = $service->calculateDiscount($price);          $this->asnamespace Tests\Unit;  use PHPUnit\Framework\TestCase; use App\Services\DiscountService;  class DiscountServiceTest extends TestCase {     public function test_calculate_discount()     {         $price = 100;         $expectedDiscount = 90; // 10% скидки          $service = new DiscountService();         $actualDiscount = $service->calculateDiscount($price);          $this->assertEquals($expectedDiscount, $actualDiscount);     } } sertEquals($expectedDiscount, $actualDiscount);     } }

Здесь тестируем метод calculateDiscount. 100 рублей на входе — 90 на выходе. Всё по плану.

Интеграционные тесты

Интеграционные тесты — это когда ты смотришь, как всё взаимодействует в связке. Вот у тебя есть сервис, который лезет в БД, обращается к внешнему API и возвращает что-то вкусное. Тут юнит-тесты уже не помогут — нужно посмотреть на всю картину в целом.

Например, есть сервис, который получает данные от API и сохраняет их в базу. Проверим, как это работает:

namespace Tests\Feature;  use Tests\TestCase; use Illuminate\Foundation\Testing\RefreshDatabase; use App\Services\ExternalApiService;  class ApiIntegrationTest extends TestCase {     use RefreshDatabase;      public function test_external_api_data_is_saved_to_database()     {         $this->mock(ExternalApiService::class, function ($mock) {             $mock->shouldReceive('fetchData')                  ->once()                  ->andReturn([                      'name' => 'Test Item',                      'price' => 100                  ]);         });          $response = $this->get('/api/fetch-data');          $response->assertStatus(200);         $this->assertDatabaseHas('items', [             'name' => 'Test Item',             'price' => 100         ]);     } }

Здесь мы имитируем то, что наш API вернул данные, и проверяем, что они сохранились в базе.

Функциональные тесты

Функциональные тесты — это взгляд на приложения глазами пользователя. Тут пригодится Laravel Dusk — инструмент для браузерных тестов.

Допустим, есть форма входа. Проверим, что она работает корректно:

namespace Tests\Browser;  use Laravel\Dusk\Browser; use Tests\DuskTestCase;  class LoginTest extends DuskTestCase {     public function test_user_can_login()     {         $this->browse(function (Browser $browser) {             $browser->visit('/login')                     ->type('email', 'test@example.com')                     ->type('password', 'password')                     ->press('Login')                     ->assertPathIs('/home');         });     } }

Этот тест имитирует реального пользователя: он заходит на страницу логина, вводит email и пароль, а затем проверяет, что после успешного входа его перенаправляют на страницу /home.

Тестирование API

Если есть API его нужно его тестировать, то ларавелл умеет проверять JSON-запросы и ответы. Вот, например, как мы проверим список продуктов:

namespace Tests\Feature;  use Tests\TestCase;  class ProductsApiTest extends TestCase {     public function test_get_products()     {         $response = $this->getJson('/api/products');          $response->assertStatus(200)                  ->assertJsonStructure([                      '*' => ['id', 'name', 'price']                  ]);     } }

Этот тест проверяет, что API возвращает список продуктов с нужными полями.

Примеры использования

Тестирование отправки письма при успешной регистрации

Следующий пример — это классическая ситуация, когда при регистрации нового пользователя система должна отправить приветственное письмо. Нужно убедиться, что оно действительно отправляется.

namespace Tests\Feature;  use Tests\TestCase; use Illuminate\Support\Facades\Mail; use App\Mail\WelcomeEmail; use App\Models\User; use Illuminate\Foundation\Testing\RefreshDatabase;  class WelcomeEmailTest extends TestCase {     use RefreshDatabase;      public function test_welcome_email_is_sent_upon_registration()     {         Mail::fake();          // Выполняем регистрацию пользователя         $response = $this->post('/register', [             'name' => 'Ivan Ivanov',             'email' => 'ivan@example.com',             'password' => 'password123',             'password_confirmation' => 'password123'         ]);          // Проверяем, что пользователь успешно создан         $this->assertDatabaseHas('users', ['email' => 'ivan@example.com']);          // Проверяем, что письмо было отправлено         Mail::assertSent(WelcomeEmail::class, function ($mail) {             return $mail->hasTo('ivan@example.com');         });     } }

Тест позволит убедиться, что система действительно отправляет email каждому новому пользователю.

Тестирование удаления записей из базы данных

Предположим, есть CRUD-система для управления записями. Нужно убедиться, что записи корректно удаляются, а также правильно обрабатываются сопутствующие данные. Протестируем сценарий удаления записи и проверим, что данные действительно ушли в никуда.

namespace Tests\Feature;  use Tests\TestCase; use Illuminate\Foundation\Testing\RefreshDatabase; use App\Models\Post;  class PostDeletionTest extends TestCase {     use RefreshDatabase;      public function test_post_can_be_deleted()     {         // Создаем пост         $post = Post::factory()->create();          // Отправляем запрос на удаление         $response = $this->delete('/posts/' . $post->id);          // Проверяем успешный статус и редирект         $response->assertStatus(302);         $response->assertRedirect('/posts');          // Проверяем, что запись удалена из базы         $this->assertDatabaseMissing('posts', ['id' => $post->id]);     } }

Этот тест проверяет:

  1. Успешное удаление записи.

  2. Отсутствие записи в базе данных после удаления.

Тест защитит от сценариев, когда запись вроде бы удаляется, но остаётся в базе.


Всех желающих приглашаем на открытый урок «Использование GraphQL в Laravel проектах». На нем сравним RESTFul и Graphql; предоставим API, используя Graphql; а также посмотрим, как работать с Graphql на фронтэнде. Записаться на урок можно на странице курса «Framework Laravel».


ссылка на оригинал статьи https://habr.com/ru/articles/849962/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *