Artiklid

Siit saate teada, kuidas teha Laravelis teste lihtsate näidete abil, kasutades PHPUnit ja PEST

Automaattestide või ühikutestide puhul on mis tahes programmeerimiskeeles kaks vastandlikku arvamust:

  • Ajaraiskamine
  • Ilma selleta ei saa

Seega püüame selle artikliga veenda esimest, eriti näidates, kui lihtne on Laravelis automatiseeritud testimisega alustada.

Kõigepealt räägime "miks" ja siis vaatame mõnda näidet selle kohta, kuidas.

Miks me vajame automatiseeritud testimist?

Automaattestid käitavad koodi osi ja teatavad kõigist vigadest. See on kõige lihtsam viis nende kirjeldamiseks. Kujutage ette, et käivitate rakenduses uue funktsiooni ja seejärel läheks isiklik roboti assistent ja testiks uut funktsiooni käsitsi, kontrollides samal ajal, kas uus kood ei riku mõnda vana funktsiooni.

See on peamine eelis: kõigi funktsioonide automaatne uuesti testimine. See võib tunduda lisatööna, kuid kui te ei käsi "robotil" seda teha, peaksime seda ka käsitsi tegema, eks? 

Või võidakse välja anda uusi funktsioone ilma nende toimimist testimata, lootes, et kasutajad teavitavad vigadest.

Automaattestid võivad anda meile mitmeid eeliseid:

  • Säästke käsitsi testimise aega;
  • Need võimaldavad säästa aega nii uue juurutatud funktsiooni kui ka konsolideeritud funktsioonide pealt, vältides regressiooni;
  • Korrutage see eelis kõigi uute ja juba rakendatud funktsioonidega;
  • Eelmised kolm punkti kehtivad iga uue versiooni kohta;
  • ...

Proovige kujutleda oma rakendust aasta või kahe pärast koos uute arendajatega, kes ei tea eelmistel aastatel kirjutatud koodi ega isegi seda, kuidas seda testida. 

Meie esimesed automatiseeritud testid

Esimese sooritamiseks automatiseeritud testimine Laravelis, ei pea te koodi kirjutama. Jah, sa lugesid õigesti. Kõik on juba eelinstallis konfigureeritud ja ette valmistatuddefiLaraveli nite, sealhulgas kõige esimene põhinäide.

Võite proovida installida Laraveli projekti ja käivitada kohe esimesed testid:

laravel new project
cd project
php artisan test

See peaks teie konsoolis olema tulemus:

Kui heidame pilgu eeldefiLaraveli õhtu /tests, meil on kaks faili:

testid/Feature/ExampleTest.php :

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

Siin toimuva mõistmiseks ei pea te teadma mingit süntaksit: laadige avaleht ja kontrollige, kas olekukood on HTTP è "200 OK".

Tuntud ka kui meetodi nimetus test_the_application_returns_a_successful_response() muutub testitulemuste vaatamisel loetavaks tekstiks, asendades lihtsalt allajoonitud sümboli tühikuga.

testid/Unit/ExampleTest.php :

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

Tundub veidi mõttetu, kontrollida, kas see on tõsi? 

Konkreetselt ühikutestidest räägime veidi hiljem. Praegu peate mõistma, mis igas testis üldiselt toimub.

  • Iga kaustas olev testfail /tests on PHP klass, mis laiendab TestCase'i PHPUnit
  • Igas klassis saate luua mitu meetodit, tavaliselt ühe meetodi olukorra testimiseks
  • Iga meetodi puhul on kolm tegevust: olukorra ettevalmistamine, seejärel tegutsemine ja seejärel kontrollimine (kinnitamine), kas tulemus on ootuspärane

Struktuuriliselt on see kõik, mida pead teadma, kõik muu sõltub konkreetsetest asjadest, mida soovite testida.

Tühja testklassi loomiseks käivitage lihtsalt see käsk:

php artisan make:test HomepageTest

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

Nüüd vaatame, mis juhtub, kui testkood Laravelis ebaõnnestub

Vaatame nüüd, mis juhtub, kui testiväited ei anna oodatud tulemust.

Muudame näidistestid järgmisteks:

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

Ja nüüd, kui käivitame käsu php artisan test uuesti:

 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

Seal on kaks ebaõnnestunud testi, mis on tähistatud kui FAIL. Allpool on selgitused ja nooled, mis osutavad ebaõnnestunud testide täpsele reale. Vead näidatakse sel viisil.

Näide: registreerimisvormi koodi testimine Laravelis

Oletame, et meil on vorm ja me peame testima erinevaid juhtumeid: kontrollime, kas see ebaõnnestub vigaste andmetega, kontrollime, kas see õnnestub õige sisendiga jne.

Ametlik stardikomplekt autor Laravel Breeze sisaldab i selle funktsionaalsuse testimine. Vaatame mõnda näidet sealt:

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

Siin on meil ühes klassis kaks testi, kuna mõlemad on seotud registreerimisvormiga: üks kontrollib, kas vorm on õigesti laaditud ja teine, kas esitamine toimib hästi.

Tutvume veel kahe tulemuse kontrollimise meetodiga, veel kahe väitega: $this->assertAuthenticated()$response->assertRedirect(). Saate kontrollida kõiki saadaolevaid väiteid ametlikus dokumentatsioonis PHPUnit e Laraveli vastus . Pange tähele, et sellel teemal esineb mõningaid üldisi väiteid $this, samas kui teised kontrollivad konkreetset $responsemarsruudikõnest.

Teine oluline asi on use RefreshDatabase;avaldus koos kriipsuga, mis on lisatud klassi kohale. See on vajalik, kui testtoimingud võivad andmebaasi mõjutada, nagu käesolevas näites, lisab logimine andmebaasi uue kirje usersandmebaasi tabel. Selleks peaksite looma eraldi testandmebaasi, mida värskendatakse php artisan migrate:freshiga kord, kui teste tehakse.

Teil on kaks võimalust: luua füüsiliselt eraldi andmebaas või kasutada mälusisest SQLite'i andmebaasi. Mõlemad on failis konfigureeritud phpunit.xmlvaikimisi ette nähtuddefinita koos Laravel. Täpsemalt vajate seda osa:

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

Vaata DB_CONNECTIONDB_DATABASEmilliseid kommenteeritakse? Kui teie serveris on SQLite, on kõige lihtsam toiming lihtsalt nende ridade kommentaaride tühistamine ja teie testid töötavad selle mälusisese andmebaasiga.

Selles testis ütleme, et kasutaja autentimine õnnestub ja suunatakse õigele kodulehele, kuid saame testida ka tegelikke andmeid andmebaasis.

Lisaks sellele koodile:

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

Saame ka kasutada andmebaasi testimise väited ja tehke midagi sellist:

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

Sisselogimislehe näide

Vaatame nüüd veel ühte näidet Laravel Breeze'i sisselogimislehest

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

See puudutab sisselogimisvormi. Loogika sarnaneb registreerimisega, eks? Kuid kahe meetodi asemel kolm, nii et see on näide nii heade kui ka halbade stsenaariumide testimisest. Seega on levinud loogika, et peaksite katsetama mõlemat juhtumit: millal läheb hästi ja millal ebaõnnestuvad.

Innovatsiooni uudiskiri
Ärge jätke ilma kõige olulisematest uuendustest. Registreeruge, et saada neid meili teel.

Selles testis näete ka selle kasutamist Andmebaasi tehased : Laravel loob võltskasutaja ( uuesti teie värskendatud testide andmebaasis ) ja proovib seejärel õigete või valede mandaatidega sisse logida.

Taas genereerib Laravel tehase eeldefinita valeandmetega Usermudel, väljaspool karpi.

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

Näete, kui palju asju valmistab Laravel ise, nii et kas meil oleks lihtne testima hakata?

Nii et kui me teostame php artisan testpärast Laravel Breeze'i installimist peaksime nägema midagi sellist:

 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

Funktsionaalsed testid võrreldes ühikutestide ja teistega

Olete alamkaustu näinud tests/Feature e tests/Unit ?. 

Mis vahe neil on? 

Ülemaailmselt on väljaspool Laraveli/PHP ökosüsteemi mitut tüüpi automatiseeritud testimist. Võite leida selliseid termineid:

  • Ühikutestid
  • Funktsioonide testimine
  • Integratsioonitestid
  • Funktsionaalsed testid
  • End-to-end testimine
  • Vastuvõtu testid
  • Suitsu testid
  • jne.

See kõlab keeruliselt ja tegelikud erinevused seda tüüpi testide vahel on mõnikord hägused. Sellepärast on Laravel lihtsustanud kõiki neid segaseid termineid ja rühmitanud need kaheks: üksus/funktsioon.

Lihtsamalt öeldes püüavad funktsioonitestid täita teie rakenduste tegelikku funktsionaalsust: hankida URL, kutsuda API, jäljendada täpset käitumist, näiteks vormi täitmist. Funktsioonitestid teostavad tavaliselt samu või sarnaseid toiminguid, mida iga projekti kasutaja teeks reaalses elus käsitsi.

Ühiktestidel on kaks tähendust. Üldiselt võite avastada, et iga automaattesti nimetatakse üksuse testimiseks ja kogu protsessi võib nimetada üksuse testimiseks. Kuid funktsionaalsuse ja üksuse kontekstis on see protsess konkreetse mitteavaliku koodiüksuse katsetamine eraldi. Näiteks on teil Laraveli klass meetodiga, mis arvutab midagi, näiteks tellimuse koguhinda koos parameetritega. Seetõttu teataks ühikutestis, kas sellest meetodist (koodiühikust) saadakse õiged tulemused erinevate parameetritega.

Ühiku testi loomiseks peate lisama lipu:

php artisan make:test OrderPriceTest --unit

Loodud kood on sama, mis üksuseeelsel testildefiLaraveli süsteem:

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

Nagu näete, pole seda olemas RefreshDatabase, ja see on üks defilevinumad ühikutesti määratlused: see ei puuduta andmebaasi, see töötab "musta kastina", mis on isoleeritud töötavast rakendusest.

Proovides jäljendada varem mainitud näidet, kujutame ette, et meil on teenindusklass OrderPrice.

app/Services/OrderPriceService.php:

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

Seejärel võiks ühikutest välja näha umbes selline:

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
}

Minu isikliku kogemuse põhjal Laraveli projektidega on enamik teste funktsioonitestid, mitte ühikutestid. Esiteks peate testima, kas teie rakendus töötab nii, nagu päris inimesed seda kasutaksid.

Järgmiseks, kui teil on spetsiaalsed arvutused või loogika, saate seda teha definire ühikuna, parameetritega saab luua spetsiaalselt selle jaoks ühikteste.

Mõnikord nõuab testide kirjutamine koodi enda muutmist ja selle ümbertöötamist, et muuta see "testitavamaks": üksuste eraldamine eriklassideks või meetoditeks.

Millal/kuidas teste teha?

Mis on selle tegelik kasu php artisan test, millal peaksite seda käivitama?

Sõltuvalt teie ettevõtte töövoost on erinevaid lähenemisviise, kuid üldiselt peate enne viimaste koodimuudatuste hoidlasse saatmist veenduma, et kõik testid on "rohelised" (st veavabad).

Seejärel töötate oma ülesandega kohapeal ja kui arvate, et olete lõpetanud, käivitage mõned testid, et veenduda, et te pole midagi rikkunud. Pidage meeles, et teie kood võib põhjustada vigu mitte ainult teie loogikas, vaid ka tahtmatult rikkuda mõnda muud käitumist kellegi teise ammu kirjutatud koodis.

Kui astume sammu edasi, on võimalik automatiseerida palju asju. Erinevate CI/CD tööriistade abil saate määrata testid, mida käivitada iga kord, kui keegi teatud Giti harus muudatusi edastab või enne koodi tootmisharuga ühendamist. Lihtsaim töövoog oleks kasutada Githubi toiminguid eraldi video mis seda tõestab.

Mida peaksite testima?

Selle kohta, kui suur peaks olema nn “testi katvus”, on erinevaid arvamusi: proovige igal lehel iga võimalikku toimingut ja juhtumit või piirduge tööga kõige olulisemate osadega.

Tegelikult nõustun siin inimestega, kes süüdistavad automatiseeritud testimist, et see võtab rohkem aega kui toob tegelikku kasu. See võib juhtuda, kui kirjutate testid iga üksikasja kohta. Sellegipoolest võib teie projekt seda nõuda: põhiküsimus on "mis on võimaliku vea hind".

Teisisõnu, peate seadma oma testimistööd prioriteediks, esitades küsimuse „Mis juhtuks, kui see kood ebaõnnestub?” Kui teie maksesüsteemis on vigu, mõjutab see ettevõtet otseselt. Nii et kui teie rollide/õiguste funktsionaalsus on katki, on see suur turvaprobleem.

Mulle meeldib, kuidas Matt Stauffer konverentsil ütles: "Kõigepealt peate katsetama asju, mis ebaõnnestumise korral teid töölt vallandaksid." Muidugi on see liialdus, kuid saate aru: proovige esmalt olulisi asju. Ja siis muid funktsioone, kui teil on aega.

PEST: uus alternatiiv PHPUnitile

Kõik ülaltoodud näited põhinevad Laraveli eeltestimise tööriistaldefiõhtupoolik: PHPUnit . Kuid aastate jooksul on ökosüsteemi ilmunud muid tööriistu ja üks uusimaid populaarseid on KAHJURI . Loodud Laraveli ametliku töötaja poolt Nuno Maduro , eesmärk on süntaksit lihtsustada, muutes testide jaoks koodi kirjutamise veelgi kiiremaks.

Kapoti all see jookseb su Täiendava kihina PHPUnit üritab minimeerida mõningaid eelnevalt korduvaid osidefiPHPUniti koodi lõpp.

Vaatame näidet. Pidage meeles funktsioonide testimise eelset klassidefinited Laravelis? Tuletan teile meelde:

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

Kas tead, kuidas näeks sama test välja PESTiga?

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

Jah, ÜKS koodirida ja kõik. Seega on PEST-i eesmärk eemaldada üldkulud:

  • Klasside ja meetodite loomine kõige jaoks;
  • Testjuhtumi laiendus;
  • Pannes toimingud eraldi ridadele: PESTis saate need kokku aheldada.

Laravelis PEST-testi genereerimiseks peate määrama täiendava lipu:

php artisan make:test HomepageTest --pest

Selle kirjutamise seisuga on PEST Laraveli arendajate seas üsna populaarne, kuid see on teie isiklik eelistus, kas kasutada seda lisatööriista ja õppida selle süntaksit, aga ka PHPUniti märkust.

BlogInnovazione.it

Innovatsiooni uudiskiri
Ärge jätke ilma kõige olulisematest uuendustest. Registreeruge, et saada neid meili teel.

Viimased artiklid

Veeam pakub lunavarale kõige põhjalikumat tuge alates kaitsest kuni reageerimise ja taastamiseni

Veeami Coveware jätkab küberväljapressimise juhtumitele reageerimise teenuste pakkumist. Coveware pakub kohtuekspertiisi ja heastamisvõimalusi…

Aprill 23 2024

Roheline ja digitaalne revolutsioon: kuidas ennustav hooldus muudab nafta- ja gaasitööstust

Ennustav hooldus muudab nafta- ja gaasisektori pöördeliseks uuendusliku ja ennetava lähenemisega tehaste juhtimisele.…

Aprill 22 2024

Ühendkuningriigi monopolivastane regulaator tõstab BigTechi häire GenAI pärast

Ühendkuningriigi CMA on väljastanud hoiatuse Big Techi käitumise kohta tehisintellekti turul. Seal…

Aprill 18 2024

Casa Green: energiarevolutsioon jätkusuutliku tuleviku nimel Itaalias

Euroopa Liidu poolt hoonete energiatõhususe suurendamiseks koostatud roheliste majade dekreet on lõpetanud oma seadusandliku protsessi…

Aprill 18 2024