Cikkek

Tanulja meg, hogyan végezzen teszteket Laravelben egyszerű példákon keresztül, PHPUnit és PEST használatával

Ami az automatizált teszteket vagy az egységteszteket illeti, bármely programozási nyelven két ellentétes vélemény létezik:

  • elvesztegetett idő
  • Nem lehet nélküle

Tehát ezzel a cikkel megpróbáljuk meggyőzni az előbbit, különösen annak bemutatásával, hogy milyen könnyű elkezdeni az automatizált tesztelést a Laravelben.

Először beszéljünk a „miért”-ről, majd lássunk néhány példát a hogyanra.

Miért van szükségünk automatizált tesztelésre?

Az automatizált tesztek futtatják a kód egyes részeit, és jelentenek minden hibát. Ez a legegyszerűbb módja annak, hogy leírjuk őket. Képzelje el, hogy bevezet egy új funkciót egy alkalmazásban, majd egy személyi robotasszisztens elmegy, és manuálisan teszteli az új funkciót, miközben azt is teszteli, hogy az új kód nem töri-e meg a régi funkciókat.

Ez a fő előnye: minden funkció automatikus újratesztelése. Ez többletmunkának tűnhet, de ha nem mondod a „robotnak”, hogy csinálja meg, akkor vagy manuálisan kell megtenni, nem? 

Vagy új funkciók is megjelenhetnek anélkül, hogy tesztelnék, hogy működnek-e, remélve, hogy a felhasználók jelenteni fogják a hibákat.

Az automatizált tesztek számos előnnyel járhatnak:

  • Takarítson meg kézi tesztelési időt;
  • Lehetővé teszik, hogy időt takarítson meg mind az újonnan implementált, mind a konszolidált függvényeknél a regresszió elkerülésével;
  • Ezt az előnyt megsokszorozhatja az összes új és már megvalósított szolgáltatással;
  • Az előző három pont minden új verzióra vonatkozik;
  • ...

Próbáld elképzelni az alkalmazásodat egy-két év múlva, új fejlesztőkkel a csapatban, akik nem ismerik a korábbi években írt kódot, vagy még azt sem, hogyan teszteljék azt. 

Első automatizált tesztjeink

Az első végrehajtásához automatizált tesztelés a Laravelben, nem kell kódot írnia. Igen, jól olvastad. Már az előtelepítés során minden konfigurálva és előkészítve vandefiLaravel vége, beleértve a legelső alappéldát is.

Megpróbálhat egy Laravel projektet telepíteni, és azonnal lefuttathatja az első teszteket:

laravel new project
cd project
php artisan test

Ennek az eredménynek kell lennie a konzolon:

Ha megnézzük az elődefiLaravel éjszakája /tests, két fájlunk van:

tesztek/Feature/ExampleTest.php :

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

Nem kell semmilyen szintaxist ismernie ahhoz, hogy megértse, mi folyik itt: töltse be a kezdőlapot, és ellenőrizze, hogy az állapotkód HTTP è "200 OK".

Metódus néven is ismert test_the_application_returns_a_successful_response() olvasható szöveggé válik, amikor megnézi a teszteredményeket, egyszerűen az aláhúzás jelének szóközzel történő helyettesítésével.

tesztek/Unit/ExampleTest.php :

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

Kicsit értelmetlennek tűnik, ellenőrizni, hogy ez igaz-e? 

Kifejezetten az egységtesztekről egy kicsit később fogunk beszélni. Egyelőre meg kell értenie, hogy általában mi történik az egyes tesztekben.

  • Minden tesztfájl a mappában /tests egy PHP osztály, amely kiterjeszti a TestCase-t PHPUnit
  • Minden osztályon belül több metódust is létrehozhat, általában egy módszert egy helyzet tesztelésére
  • Mindegyik módszeren belül három lépés van: a helyzet előkészítése, majd cselekvés, majd annak ellenőrzése (megerősítése), hogy az eredmény a vártnak megfelelő-e.

Szerkezetileg ennyit kell tudnod, minden más attól függ, hogy pontosan milyen dolgokat szeretne tesztelni.

Üres tesztosztály létrehozásához egyszerűen futtassa ezt a parancsot:

php artisan make:test HomepageTest

A fájl létrejön 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);
    }
}

Most pedig nézzük meg, mi történik, ha egy tesztkód meghiúsul a Laravelben

Lássuk most, mi történik, ha a teszt állításai nem adják vissza a várt eredményt.

Változtassuk meg a példateszteket erre:

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);
    }
}

És most, ha futtatjuk a parancsot php artisan test újra:

 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

Két sikertelen teszt van SIKERTELEN jelöléssel, az alábbi magyarázatokkal és a nyilakkal, amelyek a sikertelen tesztek pontos sorára mutatnak. A hibákat így jelezzük.

Példa: A regisztrációs űrlap kódjának tesztelése a Laravelben

Tegyük fel, hogy van egy űrlapunk, és különféle eseteket kell tesztelnünk: ellenőrizzük, hogy nem sikerül-e érvénytelen adatokkal, ellenőrizzük, hogy a megfelelő bevitellel sikerül-e, stb.

A hivatalos kezdőkészlet írta Laravel Breeze magában foglalja az i a benne lévő funkcionalitás tesztelése. Nézzünk néhány példát onnan:

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);
    }
}

Itt két teszt van egy osztályban, mivel mindkettő a regisztrációs laphoz kapcsolódik: az egyik azt ellenőrzi, hogy az űrlap megfelelően van-e betöltve, a másik pedig azt, hogy a beadás jól működik-e.

Ismerkedjünk meg még két módszerrel az eredmény ellenőrzésére, még két állítást: $this->assertAuthenticated()$response->assertRedirect(). Az összes elérhető állítást ellenőrizheti a hivatalos dokumentációjában PHPUnit e LaravelResponse . Ne feledje, hogy néhány általános állítás előfordul a témával kapcsolatban $this, míg mások ellenőrzik a konkrét $responseaz útvonalhívásból.

Egy másik fontos dolog a use RefreshDatabase;utasítás, a körvonallal, beszúrva az osztály fölé. Ez akkor szükséges, ha a tesztműveletek hatással lehetnek az adatbázisra, mint ebben a példában, a naplózás új bejegyzést ad az adatbázisba usersadatbázis tábla. Ehhez létre kell hoznia egy külön tesztadatbázist, amelyet frissíteni fog php artisan migrate:freshminden alkalommal, amikor a teszteket lefuttatják.

Két lehetőség közül választhat: hozzon létre fizikailag egy külön adatbázist, vagy használjon egy memórián belüli SQLite adatbázist. Mindkettő be van állítva a fájlban phpunit.xmlalapértelmezés szerint biztosítottdefinita vele Laravel. Pontosabban erre a részre van szüksége:

<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>

Lásd a DB_CONNECTIONDB_DATABASEmelyiket kommentálják? Ha SQLite van a kiszolgálón, a legegyszerűbb művelet az, ha egyszerűen töröljük ezeket a sorokat, és a tesztek a memórián belüli adatbázison futnak.

Ebben a tesztben azt mondjuk, hogy a felhasználó hitelesítése sikeresen megtörtént és a megfelelő kezdőlapra kerül átirányításra, de tesztelhetjük az adatbázisban lévő tényleges adatokat is.

Ezen a kódon kívül:

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

Használhatjuk is az adatbázisteszt állításai és csinálj valami ilyesmit:

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

Példa a bejelentkezési oldalra

Lássunk most egy másik példát a Laravel Breeze bejelentkezési oldalára

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();
    }
}

A bejelentkezési űrlapról van szó. A logika hasonló a regisztrációhoz, nem? De kettő helyett három módszer, tehát ez egy példa a jó és a rossz forgatókönyvek tesztelésére. Tehát a közös logika az, hogy mindkét esetet tesztelni kell: amikor a dolgok jól mennek, és amikor nem.

Innovációs hírlevél
Ne maradjon le az innovációval kapcsolatos legfontosabb hírekről. Regisztráljon, hogy megkapja őket e-mailben.

Továbbá, amit ebben a tesztben lát, az a használata Adatbázisgyárak : Laravel hamis felhasználót hoz létre ( ismét a frissített tesztadatbázisban ), majd megpróbál bejelentkezni, helyes vagy helytelen hitelesítő adatokkal.

Ismét Laravel generálja a gyári elődefinita hamis adatokkal a Usermodell, dobozon kívül.

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),
        ];
    }
}

Látod, hány dolgot készít elő maga Laravel, így könnyű lenne elkezdenünk tesztelni?

Tehát ha végrehajtjuk php artisan testa Laravel Breeze telepítése után valami ilyesmit kell látnunk:

 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

Funkcionális tesztek összehasonlítva az egységtesztekkel és másokkal

Láttad az almappákat tests/Feature e tests/Unit ?. 

Mi a különbség köztük? 

Globálisan, a Laravel/PHP ökoszisztémán kívül számos típusú automatizált tesztelés létezik. Ilyen kifejezéseket találhat:

  • Egységtesztek
  • Funkciótesztelés
  • Integrációs tesztek
  • Funkcionális tesztek
  • Végpontok közötti tesztelés
  • Átvételi tesztek
  • Füstvizsgálatok
  • stb.

Bonyolultnak hangzik, és az ilyen típusú tesztek közötti tényleges különbségek néha elmosódnak. Ezért a Laravel leegyszerűsítette ezeket a zavaró kifejezéseket, és két csoportba csoportosította őket: egység/szolgáltatás.

Egyszerűen fogalmazva, a funkciótesztek megpróbálják végrehajtani az alkalmazások tényleges funkcionalitását: lekérni az URL-t, meghívni az API-t, utánozni a pontos viselkedést, például az űrlap kitöltését. A szolgáltatástesztek általában ugyanazokat vagy hasonló műveleteket hajtják végre, mint a projekt bármely felhasználója manuálisan, a való életben.

Az egységteszteknek két jelentése van. Általában azt tapasztalhatja, hogy minden automatizált tesztet „egységtesztelésnek” neveznek, és az egész folyamatot „egységtesztelésnek” nevezhetjük. De a funkcionalitás és az egység összefüggésében ez a folyamat egy adott, nem nyilvános kódegység elkülönített teszteléséről szól. Például van egy Laravel osztályod egy metódussal, amely kiszámít valamit, például a teljes rendelési árat paraméterekkel. Ezért az egységteszt kimondja, hogy az adott módszerből (kódegységből) helyes eredményeket adnak-e vissza, különböző paraméterekkel.

Egységteszt létrehozásához hozzá kell adnia egy jelzőt:

php artisan make:test OrderPriceTest --unit

A generált kód megegyezik az egység előtti tesztteldefiLaravel rendszer:

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

Amint látja, nem létezik RefreshDatabase, és ez az egyik defileggyakoribb egységteszt definíciók: nem érinti az adatbázist, „fekete dobozként” működik, elszigetelve a futó alkalmazástól.

Próbáljuk utánozni a korábban említett példát, képzeljük el, hogy van egy szolgáltatási osztályunk OrderPrice.

app/Services/OrderPriceService.php:

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

Ezután az egységteszt valahogy így nézhet ki:

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
}

A Laravel projektekkel kapcsolatos személyes tapasztalataim szerint a tesztek túlnyomó többsége jellemzőteszt, nem egységteszt. Először is meg kell vizsgálnia, hogy az alkalmazás működik-e, ahogyan azt valódi emberek használnák.

Ezután, ha speciális számításai vagy logikája van, megteheti definire egységként, paraméterekkel, kifejezetten erre lehet egységteszteket készíteni.

Néha a tesztek megírásához magának a kódnak a módosítása és újrafeldolgozása szükséges, hogy „tesztelhetőbbé” tegye: az egységeket speciális osztályokra vagy metódusokra kell szétválasztani.

Mikor/hogyan kell teszteket végezni?

Mi ennek a tényleges haszna php artisan test, mikor kell futtatni?

Különféle megközelítések léteznek, az üzleti munkafolyamattól függően, de általában meg kell győződnie arról, hogy minden teszt „zöld” (azaz hibamentes), mielőtt a végső kódmódosításokat a tárba küldi.

Ezután helyileg dolgozik a feladaton, és amikor úgy gondolja, hogy végzett, futtasson néhány tesztet, hogy megbizonyosodjon arról, hogy nem rontott-e el semmit. Ne feledje, hogy a kódja nem csak a logikájában okozhat hibákat, hanem akaratlanul is megtörhet más viselkedést valaki más régebben írt kódjában.

Ha egy lépéssel tovább lépünk, lehetséges az automatizálás sok dolgokat. A különféle CI/CD-eszközökkel meghatározhatja a futtatandó teszteket, amikor valaki módosításokat hajt végre egy adott Git-ágon, vagy mielőtt a kódot egyesítené az éles ágba. A legegyszerűbb munkafolyamat a Github Actions használata lenne külön videó ami azt bizonyítja.

Mit kell tesztelni?

Arról, hogy mekkora legyen az úgynevezett „tesztlefedettség”, megoszlanak a vélemények: minden lehetséges műveletet és esetet próbáljon ki minden oldalon, vagy korlátozza a munkát a legfontosabb részekre.

Valójában itt értek egyet azokkal az emberekkel, akik azzal vádolják, hogy az automatizált tesztelés több időt vesz igénybe, mint amennyi tényleges hasznot hoz. Ez megtörténhet, ha minden egyes részlethez teszteket ír. Ennek ellenére a projektje megkövetelheti: a fő kérdés az, hogy „mi az ára a potenciális hibának”.

Más szavakkal, fontossági sorrendbe kell állítania a tesztelési erőfeszítéseket a következő kérdéssel: „Mi történne, ha ez a kód meghiúsulna?” Ha a fizetési rendszerben hibák vannak, az közvetlenül hatással lesz az üzletre. Tehát ha a szerepkörök/jogosultságai funkcionalitása megszakad, az óriási biztonsági probléma.

Tetszik, ahogy Matt Stauffer így fogalmazott egy konferencián: „Először azokat a dolgokat kell tesztelni, amelyek kudarc esetén kirúgnának a munkából.” Persze ez túlzás, de érted: először próbáld ki a fontos dolgokat. És akkor más funkciók, ha van ideje.

PEST: a PHPUnit új alternatívája

Az összes fenti példa a Laravel előtesztelő eszközén alapuldefivége: PHPUnit . De az évek során más eszközök is megjelentek az ökoszisztémában, és az egyik legújabb népszerű KÁRTEVŐ . A Laravel hivatalos alkalmazottja készítette Nuno Maduro , célja a szintaxis egyszerűsítése, ami még gyorsabbá teszi a tesztek kódjának írását.

A motorháztető alatt fut su A PHPUnit kiegészítő rétegként próbálja minimalizálni néhány előre ismétlődő résztdefivégét a PHPUnit kódnak.

Nézzünk egy példát. Emlékezzen a funkcióteszt előtti osztályradefinited Laravelben? Emlékeztetlek:

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);
    }
}

Tudod, hogyan nézne ki ugyanaz a teszt a PEST-tel?

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

Igen, EGY sor kód és ennyi. Tehát a PEST célja, hogy eltávolítsa a következő költségeket:

  • Osztályok és módszerek létrehozása mindenhez;
  • Teszteset kiterjesztése;
  • A műveletek külön sorokba helyezésével: PEST-en összeláncolhatja őket.

PEST teszt létrehozásához a Laravelben, meg kell adnia egy további jelzőt:

php artisan make:test HomepageTest --pest

Az írás pillanatában a PEST meglehetősen népszerű a Laravel fejlesztők körében, de az Ön személyes preferenciája, hogy használja-e ezt a kiegészítő eszközt és megtanulja-e a szintaxisát, valamint egy PHPUnit megjegyzést.

BlogInnovazione.it

Innovációs hírlevél
Ne maradjon le az innovációval kapcsolatos legfontosabb hírekről. Regisztráljon, hogy megkapja őket e-mailben.

Friss cikkek

A színező oldalak előnyei gyerekeknek – a varázslatok világa minden korosztály számára

A finom motoros készségek színezéssel történő fejlesztése felkészíti a gyerekeket olyan összetettebb készségekre, mint az írás. Kiszínezni…

Május 2 2024

A jövő itt van: Hogyan forradalmasítja a hajózási ágazat a globális gazdaságot

A haditengerészeti szektor igazi világgazdasági hatalom, amely egy 150 milliárdos piac felé navigált...

Május 1 2024

A kiadók és az OpenAI megállapodásokat írnak alá a mesterséges intelligencia által feldolgozott információáramlás szabályozására

Múlt hétfőn a Financial Times bejelentette, hogy megállapodást köt az OpenAI-val. Az FT engedélyezi világszínvonalú újságírását…

30 április 2024

Online fizetés: Így fizethet örökké a streaming szolgáltatások

Emberek milliói fizetnek a streaming szolgáltatásokért, havi előfizetési díjat fizetve. Általános vélemény, hogy Ön…

29 április 2024