членовите

Научете како да правите тестови во Ларавел со едноставни примери, користејќи PHPUnit и PEST

Кога станува збор за автоматизирани тестови или единечни тестови, во кој било програмски јазик, постојат две спротивставени мислења:

  • Трошење време
  • Не можете без него

Така, со оваа статија ќе се обидеме да го убедиме првиот, особено со тоа што ќе покажеме колку е лесно да се започне со автоматско тестирање во Ларавел.

Прво да разговараме за „зошто“, а потоа да видиме неколку примери за тоа како.

Зошто ни треба автоматско тестирање

Автоматските тестови извршуваат делови од кодот и известуваат за какви било грешки. Тоа е наједноставниот начин да ги опишете. Замислете да стартувате нова функција во апликација, а потоа личен асистент робот ќе отиде и рачно ќе ја тестира новата функција, а исто така ќе тестира дали новиот код не скрши ниту една од старите функции.

Ова е главната предност: повторно тестирање на сите функции автоматски. Ова може да изгледа како дополнителна работа, но ако не му кажете на „роботот“ да го направи тоа, алтернативно треба да го направиме рачно, нели? 

Или, пак, нови функции би можеле да бидат објавени без тестирање дали функционираат, надевајќи се дека корисниците ќе пријават грешки.

Автоматските тестови можат да ни дадат неколку предности:

  • Заштедете време за рачно тестирање;
  • Тие ви овозможуваат да заштедите време и на новата имплементирана функција и на консолидираните функции со избегнување на регресија;
  • Умножете ја оваа придобивка со сите нови функции и сите веќе имплементирани функции;
  • Претходните три точки важат за секоја нова верзија;
  • ...

Обидете се да ја замислите вашата апликација за една или две години, со нови програмери во тимот кои не го знаат кодот напишан во претходните години, па дури и како да го тестираат. 

Нашите први автоматски тестови

Да се ​​изврши првата автоматско тестирање во Ларавел, не треба да пишувате никаков код. Да, добро прочитавте. Сè е веќе конфигурирано и подготвено во прединсталацијатаdefinite of Laravel, вклучувајќи го и првиот основен пример.

Може да се обидете да инсталирате проект Laravel и веднаш да ги извршите првите тестови:

laravel new project
cd project
php artisan test

Ова треба да биде резултат во вашата конзола:

Ако погледнеме на предdefiноќта на Ларавел /tests, имаме две датотеки:

тестови/Функција/ExampleTest.php :

class ExampleTest extends TestCase
{
    public function test_the_application_returns_a_successful_response()
    {
        $response = $this->get('/');
 
        $response->assertStatus(200);
    }
}

Не треба да знаете никаква синтакса за да разберете што се случува овде: вчитајте ја почетната страница и проверете дали е кодот за статус HTTP è "200 OK".

Познато и како име на методот test_the_application_returns_a_successful_response() станува читлив текст кога ги гледате резултатите од тестот, едноставно со замена на подвлечениот симбол со празно место.

тестови/Единица/Пример Тест.php :

class ExampleTest extends TestCase
{
    public function test_that_true_is_true()
    {
        $this->assertTrue(true);
    }
}

Изгледа малку бесмислено, проверувам дали е ова вистина? 

Ќе зборуваме конкретно за единечните тестови малку подоцна. Засега, треба да разберете што генерално се случува во секој тест.

  • Секоја тест датотека во папката /tests е класа PHP што го проширува TestCase на PHPU-единица
  • Во секоја класа, можете да креирате повеќе методи, обично еден метод за тестирање на ситуацијата
  • Во секој метод има три дејства: подготовка на ситуацијата, потоа преземање акција и потоа проверка (афирмирање) дали исходот е како што се очекува

Структурно, тоа е сè што треба да знаете, сè друго зависи од точните работи што сакате да ги тестирате.

За да генерирате празна тест класа, едноставно извршете ја оваа команда:

php artisan make:test HomepageTest

Датотеката е генерирана tests/Feature/HomepageTest.php:

class HomepageTest extends TestCase
{
    // Replace this method with your own ones
    public function test_example()
    {
        $response = $this->get('/');
 
        $response->assertStatus(200);
    }
}

Сега да видиме што ќе се случи ако тест кодот не успее во Ларавел

Ајде сега да видиме што ќе се случи ако тврдењата на тестот не го вратат очекуваниот резултат.

Ајде да ги смениме примерите на тестови на ова:

class ExampleTest extends TestCase
{
    public function test_the_application_returns_a_successful_response()
    {
        $response = $this->get('/non-existing-url');
 
        $response->assertStatus(200);
    }
}
 
 
class ExampleTest extends TestCase
{
    public function test_that_true_is_false()
    {
        $this->assertTrue(false);
    }
}

И сега, ако ја извршиме командата php artisan test повторно:

 FAIL  Tests\Unit\ExampleTest
⨯ that true is true
 
 FAIL  Tests\Feature\ExampleTest
⨯ the application returns a successful response
 
---
 
• Tests\Unit\ExampleTest > that true is true
Failed asserting that false is true.
 
at tests/Unit/ExampleTest.php:16
   12▕      * @return void
   13▕      */
   14▕     public function test_that_true_is_true()
   15▕     {
➜  16▕         $this->assertTrue(false);
   17▕     }
   18▕ }
   19▕
 
• Tests\Feature\ExampleTest > the application returns a successful response
Expected response status code [200] but received 404.
Failed asserting that 200 is identical to 404.
 
at tests/Feature/ExampleTest.php:19
   15▕     public function test_the_application_returns_a_successful_response()
   16▕     {
   17▕         $response = $this->get('/non-existing-url');
   18▕
➜  19▕         $response->assertStatus(200);
   20▕     }
   21▕ }
   22▕
 
 
Tests:  2 failed
Time:   0.11s

Постојат два неуспешни теста, означени како FAIL, со објаснувања подолу и стрелки што укажуваат на точната линија на тестови што не успеале. Грешките се наведени на овој начин.

Пример: Тестирање на кодот на формуларот за регистрација во Ларавел

Да претпоставиме дека имаме формулар и треба да тестираме различни случаи: проверуваме дали не успева со невалидни податоци, проверуваме дали успева со точниот внес итн.

Официјалниот стартен комплет од Ларавел Бриз вклучува i тестирање на функционалноста во него. Ајде да погледнеме неколку примери од таму:

tests/Feature/RegistrationTest.php

use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
 
class RegistrationTest extends TestCase
{
    use RefreshDatabase;
 
    public function test_registration_screen_can_be_rendered()
    {
        $response = $this->get('/register');
 
        $response->assertStatus(200);
    }
 
    public function test_new_users_can_register()
    {
        $response = $this->post('/register', [
            'name' => 'Test User',
            'email' => 'test@example.com',
            'password' => 'password',
            'password_confirmation' => 'password',
        ]);
 
        $this->assertAuthenticated();
        $response->assertRedirect(RouteServiceProvider::HOME);
    }
}

Овде имаме два теста во една класа, бидејќи и двата се поврзани со формуларот за регистрација: еден проверува дали формуларот е правилно вчитан и друг проверува дали поднесокот работи добро.

Дозволете ни да се запознаеме со уште два методи за проверка на резултатот, уште две тврдења: $this->assertAuthenticated()$response->assertRedirect(). Можете да ги проверите сите тврдења достапни во официјалната документација на PHPU-единица e Одговор на Ларавел . Имајте на ум дека некои општи тврдења се појавуваат на оваа тема $this, додека други го проверуваат специфичното $responseод повикот на рутата.

Друга важна работа е use RefreshDatabase;изјава, со потегот, вметната над класата. Неопходно е кога тест дејствата можат да влијаат на базата на податоци, како во овој пример, логирањето додава нов запис во usersтабела со база на податоци. За ова, треба да креирате посебна база на податоци за тестирање која ќе се ажурира со php artisan migrate:freshсекој пат кога се извршуваат тестовите.

Имате две опции: физички да креирате посебна база на податоци или да користите база на податоци во меморијата SQLite. И двете се конфигурирани во датотеката phpunit.xmlобезбедено стандардноdefiнита со Laravel. Поточно, потребен ви е овој дел:

<php>
    <env name="APP_ENV" value="testing"/>
    <env name="BCRYPT_ROUNDS" value="4"/>
    <env name="CACHE_DRIVER" value="array"/>
    <!-- <env name="DB_CONNECTION" value="sqlite"/> -->
    <!-- <env name="DB_DATABASE" value=":memory:"/> -->
    <env name="MAIL_MAILER" value="array"/>
    <env name="QUEUE_CONNECTION" value="sync"/>
    <env name="SESSION_DRIVER" value="array"/>
    <env name="TELESCOPE_ENABLED" value="false"/>
</php>

Видете го DB_CONNECTIONDB_DATABASEкои се коментираат? Ако имате SQLite на вашиот сервер, наједноставната акција е едноставно да ги откоментирате тие линии и вашите тестови ќе работат против таа база на податоци во меморијата.

Во овој тест велиме дека корисникот е успешно автентициран и пренасочен на точната почетна страница, но можеме да ги тестираме и вистинските податоци во базата на податоци.

Во прилог на овој код:

$this->assertAuthenticated();
$response->assertRedirect(RouteServiceProvider::HOME);

Можеме да користиме и тврдењата за тестирање на базата на податоци и направи нешто како ова:

$this->assertDatabaseCount('users', 1);
 
// Or...
$this->assertDatabaseHas('users', [
    'email' => 'test@example.com',
]);

Пример за страницата за најавување

Ајде сега да видиме друг пример на страница за најавување со Laravel Breeze

tests/Feature/AuthenticationTest.php:

class AuthenticationTest extends TestCase
{
    use RefreshDatabase;
 
    public function test_login_screen_can_be_rendered()
    {
        $response = $this->get('/login');
 
        $response->assertStatus(200);
    }
 
    public function test_users_can_authenticate_using_the_login_screen()
    {
        $user = User::factory()->create();
 
        $response = $this->post('/login', [
            'email' => $user->email,
            'password' => 'password',
        ]);
 
        $this->assertAuthenticated();
        $response->assertRedirect(RouteServiceProvider::HOME);
    }
 
    public function test_users_can_not_authenticate_with_invalid_password()
    {
        $user = User::factory()->create();
 
        $this->post('/login', [
            'email' => $user->email,
            'password' => 'wrong-password',
        ]);
 
        $this->assertGuest();
    }
}

Се работи за формуларот за најава. Логиката е слична на регистрацијата, нели? Но, три методи наместо два, па ова е пример за тестирање на добри и лоши сценарија. Значи, заедничката логика е дека треба да ги тестирате двата случаи: кога работите одат добро и кога не успеваат.

Билтен за иновации
Не пропуштајте ги најважните вести за иновациите. Пријавете се за да ги добивате по е-пошта.

Исто така, она што го гледате во овој тест е употребата на Фабрики за бази на податоци : Laravel создава лажен корисник ( повторно, на вашата ажурирана база на податоци за тестирање ) и потоа се обидува да се најави, со точни или неточни ингеренции.

Уште еднаш, Laravel го генерира фабричкиот предdefiнита со лажни податоци за на Userмодел, надвор од кутијата.

database/factories/UserFactory.php:

class UserFactory extends Factory
{
    public function definition()
    {
        return [
            'name' => $this->faker->name(),
            'email' => $this->faker->unique()->safeEmail(),
            'email_verified_at' => now(),
            'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
            'remember_token' => Str::random(10),
        ];
    }
}

Видете, колку работи се подготвени од самиот Ларавел, па дали ќе ни биде лесно да почнеме да тестираме?

Значи, ако извршиме php artisan testпо инсталирањето на Laravel Breeze, треба да видиме вакво нешто:

 PASS  Tests\Unit\ExampleTest
✓ that true is true
 
 PASS  Tests\Feature\Auth\AuthenticationTest
✓ login screen can be rendered
✓ users can authenticate using the login screen
✓ users can not authenticate with invalid password
 
 PASS  Tests\Feature\Auth\EmailVerificationTest
✓ email verification screen can be rendered
✓ email can be verified
✓ email is not verified with invalid hash
 
 PASS  Tests\Feature\Auth\PasswordConfirmationTest
✓ confirm password screen can be rendered
✓ password can be confirmed
✓ password is not confirmed with invalid password
 
 PASS  Tests\Feature\Auth\PasswordResetTest
✓ reset password link screen can be rendered
✓ reset password link can be requested
✓ reset password screen can be rendered
✓ password can be reset with valid token
 
 PASS  Tests\Feature\Auth\RegistrationTest
✓ registration screen can be rendered
✓ new users can register
 
 PASS  Tests\Feature\ExampleTest
✓ the application returns a successful response
 
Tests:  17 passed
Time:   0.61s

Функционални тестови во споредба со единечни тестови и други

Ги видовте подпапките tests/Feature e tests/Unit ?. 

Која е разликата меѓу нив? 

На глобално ниво, надвор од екосистемот Laravel/PHP, постојат неколку типови на автоматизирано тестирање. Можете да најдете термини како:

  • Единица тестови
  • Тестирање на карактеристики
  • Тестови за интеграција
  • Функционални тестови
  • Тестирање од крај до крај
  • Тестови за прифаќање
  • Тестови за чад
  • итн.

Звучи комплицирано, а вистинските разлики помеѓу овие типови на тестови понекогаш се нејасни. Затоа Ларавел ги поедностави сите овие збунувачки термини и ги групира на два: единица/функција.

Едноставно кажано, тестовите за карактеристики се обидуваат да ја извршат вистинската функционалност на вашите апликации: земете ја URL-то, повикајте го API, имитирајте го точното однесување како пополнување на формуларот. Тестовите за карактеристики обично ги извршуваат истите или слични операции како што би направил секој корисник на проектот, рачно, во реалниот живот.

Единиците тестови имаат две значења. Во принцип, може да откриете дека секој автоматизиран тест се нарекува „тестирање на единицата“ и целиот процес може да се нарече „тестирање на единицата“. Но, во контекст на функционалноста наспроти единицата, овој процес е за тестирање на одредена нејавна единица на код, изолирано. На пример, имате класа Laravel со метод што пресметува нешто, како вкупната цена на нарачката со параметри. Според тоа, единечниот тест би навел дали се враќаат точни резултати од тој метод (единица на код), со различни параметри.

За да генерирате тест за единица, треба да додадете знаменце:

php artisan make:test OrderPriceTest --unit

Генерираниот код е ист како тестот пред единицатаdefiЛаравел систем:

class OrderPriceTest extends TestCase
{
    public function test_example()
    {
        $this->assertTrue(true);
    }
}

Како што можете да видите, не постои RefreshDatabase, а ова е едно од defiнајчести дефиниции за тест за единици: не ја допира базата на податоци, работи како „црна кутија“, изолирана од апликацијата која работи.

Обидувајќи се да го имитираме примерот што го споменав претходно, да замислиме дека имаме класа на услуги OrderPrice.

app/Services/OrderPriceService.php:

class OrderPriceService
{
    public function calculatePrice($productId, $quantity, $tax = 0.0)
    {
        // Some kind of calculation logic
    }
}

Потоа, единицата тест може да изгледа вака:

class OrderPriceTest extends TestCase
{
    public function test_single_product_no_taxes()
    {
        $product = Product::factory()->create(); // generate a fake product
        $price = (new OrderPriceService())->calculatePrice($product->id, 1);
        $this->assertEquals(1, $price);
    }
 
    public function test_single_product_with_taxes()
    {
        $price = (new OrderPriceService())->calculatePrice($product->id, 1, 20);
        $this->assertEquals(1.2, $price);
    }
 
    // More cases with more parameters
}

Според моето лично искуство со проектите на Ларавел, огромното мнозинство на тестови се Тестови за карактеристики, а не за единици. Прво, треба да тестирате дали вашата апликација работи, како што би ја користеле вистинските луѓе.

Следно, ако имаш посебни пресметки или логика можеш definire како единица, со параметри, можеш да креираш единечни тестови специјално за тоа.

Понекогаш, пишувањето тестови бара модифицирање на самиот код и негово рефакторирање за да се направи повеќе „проверлив“: одвојување на единиците во посебни класи или методи.

Кога/како да се направат тестови?

Која е вистинската употреба на ова php artisan test, кога треба да го стартувате?

Постојат различни пристапи, во зависност од работниот тек на вашиот бизнис, но генерално треба да се осигурате дека сите тестови се „зелени“ (т.е. без грешки) пред да ги турнете конечните промени на кодот во складиштето.

Потоа, работите локално на вашата задача и кога мислите дека сте готови, извршете неколку тестови за да бидете сигурни дека не сте скршиле ништо. Запомнете, вашиот код може да предизвика грешки не само во вашата сопствена логика, туку и ненамерно да скрши некое друго однесување во туѓиот код напишан одамна.

Ако одиме чекор понатаму, можно е да се автоматизира молте работи. Со различни CI/CD алатки, можете да одредите тестови да се извршуваат секогаш кога некој ќе турка промени во одредена Git гранка или пред да го спои кодот во производствената гранка. Наједноставниот работен тек би бил користењето Github Actions, јас го имам посебно видео што го докажува тоа.

Што треба да тестирате?

Постојат различни мислења за тоа колку голема треба да биде таканаречената „покриеност за тестирање“: испробајте ја секоја можна операција и случај на секоја страница или ограничете ја работата на најважните делови.

Всушност, ова е местото каде што се согласувам со луѓето кои обвинуваат дека автоматското тестирање одзема повеќе време отколку да обезбеди вистинска корист. Ова може да се случи ако напишете тестови за секој детал. Како што рече, тоа може да го бара вашиот проект: главното прашање е „која е цената на потенцијалната грешка“.

Со други зборови, треба да им дадете приоритет на вашите напори за тестирање поставувајќи го прашањето „Што би се случило ако овој код не успее? Ако вашиот систем за плаќање има грешки, тоа директно ќе влијае на бизнисот. Значи, ако функционалноста на вашите улоги/дозволи е нарушена, ова е огромен безбедносен проблем.

Ми се допаѓа како Мет Стауфер го кажа на конференција: „Прво мора да ги тестирате оние работи кои, доколку не успеат, ќе ве отпуштат од работата“. Се разбира, тоа е претерување, но ја разбирате идејата: прво пробајте ги важните работи. А потоа и други карактеристики, ако имате време.

PEST: нова алтернатива на PHPUnit

Сите горенаведени примери се засноваат на алатката за претходно тестирање на Ларавелdefiноќ: PHPU-единица . Но, со текот на годините се појавија други алатки во екосистемот и една од најновите популарни е ШТЕТНИК . Создаден од официјален вработен во Ларавел Нуно Мадуро , има за цел да ја поедностави синтаксата, правејќи го пишувањето код за тестови уште побрзо.

Под хаубата, работи su PHPUnit, како дополнителен слој, само се обидува да минимизира некои претходно повторени деловиdefiнита од кодот PHPUnit.

Ајде да погледнеме на пример. Запомнете ја класата за тестирање пред карактеристикиdefiво Ларавел? Ќе те потсетам:

namespace Tests\Feature;
 
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
 
class ExampleTest extends TestCase
{
    public function test_the_application_returns_a_successful_response()
    {
        $response = $this->get('/');
 
        $response->assertStatus(200);
    }
}

Дали знаете како би изгледал истиот тест со PEST?

test('the application returns a successful response')->get('/')->assertStatus(200);

Да, ЕДНА линија код и тоа е тоа. Значи, целта на PEST е да ги отстрани трошоците за:

  • Креирање класи и методи за сè;
  • Продолжување на тест случај;
  • Со ставање дејства на посебни линии: во PEST можете да ги ланчате заедно.

За да генерирате PEST тест во Ларавел, треба да наведете дополнително знаменце:

php artisan make:test HomepageTest --pest

Од моментот на пишување, PEST е доста популарен меѓу развивачите на Laravel, но ваша лична претпочита е дали да ја користите оваа дополнителна алатка и да ја научите нејзината синтакса, како и белешката PHPUnit.

BlogInnovazione.it

Билтен за иновации
Не пропуштајте ги најважните вести за иновациите. Пријавете се за да ги добивате по е-пошта.

Последни написи

Veeam ја има најсеопфатната поддршка за ransomware, од заштита до одговор и обновување

Coveware од Veeam ќе продолжи да обезбедува услуги за одговор на инциденти на сајбер изнуда. Coveware ќе понуди форензика и способности за санација…

Април 23 2024

Зелена и дигитална револуција: Како предвидливото одржување ја трансформира индустријата за нафта и гас

Предвидливото одржување го револуционизира секторот за нафта и гас, со иновативен и проактивен пристап кон управувањето со постројките.…

Април 22 2024

Антимонополскиот регулатор на Обединетото Кралство го покренува алармот на BigTech поради GenAI

Обединетото Кралство CMA издаде предупредување за однесувањето на Big Tech на пазарот на вештачка интелигенција. Таму…

Април 18 2024

Casa Green: енергетска револуција за одржлива иднина во Италија

Уредбата за „Case Green“, формулирана од Европската унија за подобрување на енергетската ефикасност на зградите, го заврши својот законодавен процес со…

Април 18 2024

Читајте иновации на вашиот јазик

Билтен за иновации
Не пропуштајте ги најважните вести за иновациите. Пријавете се за да ги добивате по е-пошта.

Следете нас