artikels

Learje hoe't jo testen kinne dwaan yn Laravel mei ienfâldige foarbylden, mei PHPUnit en PEST

As it giet om automatisearre tests as ienheidstests, yn elke programmeartaal, binne d'r twa tsjinoerstelde mieningen:

  • Tiidfergriemen
  • Jo kinne net sûnder

Dat, mei dit artikel sille wy besykje de eardere te oertsjûgjen, foaral troch te demonstrearjen hoe maklik it is om te begjinnen mei automatisearre testen yn Laravel.

Litte wy earst prate oer it "wêrom", en dan litte wy wat foarbylden sjen fan it hoe.

Wêrom hawwe wy automatisearre testen nedich

Automatisearre tests rinne dielen fan 'e koade en rapportearje alle flaters. Dat is de maklikste manier om se te beskriuwen. Stel jo foar dat jo in nije funksje yn in app útrolje, en dan soe in persoanlike robotassistint gean en de nije funksje manuell testje, wylst jo ek testen oft de nije koade gjin fan 'e âlde funksjes brekt.

Dit is it wichtichste foardiel: alle funksjes automatysk opnij testen. Dit kin lykje as ekstra wurk, mar as jo de "robot" net sizze om it te dwaan, moatte wy it alternatyf mei de hân dwaan, toch? 

Of nije funksjes koene wurde frijjûn sûnder te testen oft se wurkje, yn 'e hoop dat brûkers bugs sille melde.

Automatisearre tests kinne ús ferskate foardielen jaan:

  • Besparje tiid foar hantlieding;
  • Se kinne jo tiid besparje sawol op 'e nije ymplementearre funksje as op' e konsolidearre funksjes troch regression te foarkommen;
  • Fermannichfâldigje dit foardiel mei alle nije funksjes en alle funksjes al ymplementearre;
  • De foarige trije punten jilde foar elke nije ferzje;
  • ...

Besykje jo applikaasje yn in jier as twa foar te stellen, mei nije ûntwikkelders yn it team dy't de koade net kenne dy't yn foargeande jierren is skreaun, of sels hoe't jo it kinne testen. 

Us earste automatyske tests

Om útfiere de earste automatisearre testen yn Laravel, jo hoege gjin koade te skriuwen. Ja, jo lêze dat goed. Alles is al konfigureare en taret yn 'e pre-ynstallaasjedefinite of Laravel, ynklusyf it alderearste basisfoarbyld.

Jo kinne besykje in Laravel-projekt te ynstallearjen en de earste testen fuortendaliks útfiere:

laravel new project
cd project
php artisan test

Dit moat it resultaat wêze yn jo konsole:

As wy nimme in blik op de predefinacht fan Laravel /tests, wy hawwe twa triemmen:

tests/Feature/ExampleTest.php :

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

Jo hoege gjin syntaksis te witten om te begripen wat hjir bart: lade de thússide en kontrolearje oft de statuskoade HTTP is "200 OK".

Ek bekend as de metoade namme test_the_application_returns_a_successful_response() wurdt lêsbere tekst as jo de testresultaten besjen, gewoan troch it ûnderstreksymboal te ferfangen troch in spaasje.

tests/Unit/ExampleTest.php :

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

It liket in bytsje nutteloos, kontrolearje om te sjen oft dit wier is? 

Wy sille in bytsje letter spesifyk prate oer ienheidstests. Foar no moatte jo begripe wat yn 't algemien bart yn elke test.

  • Elke testtriem yn 'e map /tests is in PHP klasse dy't wreidet de TestCase fan PHPUnit
  • Binnen elke klasse kinne jo meardere metoaden oanmeitsje, meastentiids ien metoade foar in situaasje om te testen
  • Binnen elke metoade binne d'r trije aksjes: tarieding fan 'e situaasje, dan aksje en dan kontrolearje (befêstigje) oft de útkomst is lykas ferwachte

Struktureel is dat alles wat jo witte moatte, al it oare hinget ôf fan 'e krekte dingen dy't jo wolle testen.

Om in lege testklasse te generearjen, útfiere gewoan dit kommando:

php artisan make:test HomepageTest

De triem wurdt oanmakke 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);
    }
}

Litte wy no sjen wat der bart as in testkoade mislearret yn Laravel

Litte wy no sjen wat der bart as de testbewearingen it ferwachte resultaat net werombringe.

Litte wy de foarbyldtests feroarje nei dit:

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

En no, as wy it kommando útfiere php artisan test wer:

 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

D'r binne twa mislearre tests, markearre as FAIL, mei taljochtingen hjirûnder en pylken dy't wize op de krekte line fan tests dy't mislearre. Flaters wurde op dizze manier oanjûn.

Foarbyld: Testen fan registraasjeformulierkoade yn Laravel

Stel dat wy in formulier hawwe en wy moatte ferskate gefallen testen: wy kontrolearje oft it mislearret mei ûnjildige gegevens, wy kontrolearje oft it slagget mei de juste ynfier, ensfh.

De offisjele starterspakket troch Laravel Breeze omfettet i it testen fan de funksjonaliteit dêryn. Litte wy dêr wat foarbylden fan sjen:

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

Hjir hawwe wy twa tests yn ien klasse, om't se beide relatearre binne oan it registraasjeformulier: ien kontrolearret as it formulier goed laden is en in oare kontrolearret as it yntsjinjen goed wurket.

Lit ús fertroud wurde mei noch twa metoaden foar it ferifiearjen fan it resultaat, noch twa bewearingen: $this->assertAuthenticated()$response->assertRedirect(). Jo kinne kontrolearje alle bewearingen beskikber yn de offisjele dokumintaasje fan PHPUnit e LaravelResponse . Tink derom dat guon algemiene bewearingen oer it ûnderwerp foarkomme $this, wylst oaren kontrolearje de spesifike $responseút de rûte oprop.

In oar wichtich ding is de use RefreshDatabase;statement, mei de slach, ynfoege boppe de klasse. It is nedich as testaksjes de databank kinne beynfloedzje, lykas yn dit foarbyld, logging foeget in nije yngong ta yn 'e usersdatabank tabel. Hjirfoar moatte jo in aparte testdatabase meitsje wêrmei't jo bywurke wurde php artisan migrate:freshelke kear as de tests wurde útfierd.

Jo hawwe twa opsjes: fysyk meitsje in aparte databank of brûk in yn-ûnthâld SQLite databank. Beide binne konfigurearre yn it bestân phpunit.xmlstandert foarsjoendefinit mei Laravel. Spesifyk hawwe jo dit diel nedich:

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

Sjoch de DB_CONNECTIONDB_DATABASEop hokker wurde kommentearre? As jo ​​SQLite op jo tsjinner hawwe, is de ienfâldichste aksje om dizze rigels gewoan unkommentearje te litten en jo tests sille rinne tsjin dy databank yn it ûnthâld.

Yn dizze test sizze wy dat de brûker mei súkses authentisearre is en omlaat nei de juste thússide, mar wy kinne ek de eigentlike gegevens yn 'e databank testen.

Neist dizze koade:

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

Wy kinne ek brûke de databank test bewearingen en doch sa'n ding:

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

Foarbyld fan de Login side

Litte wy no in oar foarbyld sjen fan in oanmeldside mei 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();
    }
}

It giet om it oanmeldformulier. De logika is gelyk oan registraasje, krekt? Mar trije metoaden ynstee fan twa, dus dit is in foarbyld fan it testen fan sawol goede as minne senario's. Dat, de mienskiplike logika is dat jo beide gefallen moatte testen: wannear't dingen goed gean en wannear't se mislearje.

Ynnovaasje nijsbrief
Mis it wichtichste nijs oer ynnovaasje net. Meld jo oan om se fia e-post te ûntfangen.

Ek, wat jo sjogge yn dizze test is it gebrûk fan Databank Fabriken : Laravel makket falske brûker ( wer, op jo bywurke test databank ) en besiket dan oan te melden, mei juste of ferkearde referinsjes.

Wer genereart Laravel it fabryk predefinita mei falske gegevens foar de Usermodel, bûten de doaze.

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

Jo sjogge, hoefolle dingen wurde taret troch Laravel sels, dus soe it foar ús maklik wêze om te testen?

Dus as wy útfiere php artisan testnei it ynstallearjen fan Laravel Breeze, soene wy ​​sokssawat moatte sjen:

 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

Funksjonele tests fergelike mei ienheidstests en oaren

Jo hawwe de submappen sjoen tests/Feature e tests/Unit ?. 

Wat is it ferskil tusken harren? 

Wrâldwiid, bûten it Laravel / PHP-ekosysteem, binne d'r ferskate soarten automatisearre testen. Jo kinne termen fine lykas:

  • Unit tests
  • Funksje testen
  • Yntegraasje tests
  • Funksjonele tests
  • End-to-end testen
  • Akseptaasjetests
  • Smoke tests
  • ensfh.

It klinkt yngewikkeld, en de eigentlike ferskillen tusken dizze soarten testen binne soms nuansearre. Dêrom hat Laravel al dizze betiizjende termen ferienfâldige en groepearre yn twa: ienheid / funksje.

Simpelwei, funksjetests besykje de eigentlike funksjonaliteit fan jo applikaasjes út te fieren: krije de URL, skilje de API, mimik it krekte gedrach lykas it ynfoljen fan it formulier. Funksjetests fiere normaal deselde of ferlykbere operaasjes út as elke projektbrûker soe dwaan, mei de hân, yn it echte libben.

Ienheidstests hawwe twa betsjuttingen. Yn 't algemien kinne jo fine dat elke automatisearre test "ienheidstesten" wurdt neamd en it heule proses kin "ienheidstesten" wurde neamd. Mar yn 'e kontekst fan funksjonaliteit tsjin ienheid giet dit proses oer it testen fan in spesifike net-iepenbiere ienheid fan koade, yn isolemint. Jo hawwe bygelyks in Laravel-klasse mei in metoade dy't wat berekkent, lykas de totale oarderpriis mei parameters. Dêrom soe de ienheidstest oanjaan oft juste resultaten wurde weromjûn fan dy metoade (koade-ienheid), mei ferskate parameters.

Om in ienheidstest te generearjen, moatte jo in flagge tafoegje:

php artisan make:test OrderPriceTest --unit

De oanmakke koade is itselde as de pre-ienheidstestdefiLaravel systeem:

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

Sa't jo sjen kinne, it bestiet net RefreshDatabase, en dit is ien fan defimeast foarkommende ienheidstestdefinysjes: it rekket de databank net, it wurket as in "swarte doaze", isolearre fan 'e rinnende applikaasje.

Besykje it foarbyld te imitearjen dat ik earder neamde, lit ús yntinke dat wy in tsjinstklasse hawwe OrderPrice.

app/Services/OrderPriceService.php:

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

Dan kin de ienheidstest der sa útsjen:

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
}

Yn myn persoanlike ûnderfining mei Laravel-projekten binne de grutte mearderheid fan testen Featuretests, net Unit-tests. Earst moatte jo testen oft jo applikaasje wurket, lykas echte minsken it soene brûke.

Folgjende, as jo spesjale berekkeningen of logika hawwe kinne jo definire as ienheid, mei parameters, kinne jo meitsje ienheid tests spesifyk foar dat.

Soms fereasket it skriuwen fan tests it feroarjen fan de koade sels en it refactoring it om it mear "testber" te meitsjen: de ienheden skieden yn spesjale klassen as metoaden.

Wannear/hoe de tests út te fieren?

Wat is it eigentlike gebrûk fan dit php artisan test, wannear moatte jo rinne it?

D'r binne ferskate oanpak, ôfhinklik fan jo saaklike workflow, mar oer it algemien moatte jo derfoar soargje dat alle testen "grien" binne (dus flaterfrij) foardat jo de lêste koadewizigingen nei it repository triuwe.

Dan wurkje jo lokaal oan jo taak, en as jo tinke dat jo klear binne, útfiere wat tests om te soargjen dat jo neat hawwe brutsen. Unthâld, jo koade kin bugs net allinich yn jo eigen logika feroarsaakje, mar ek ûnbedoeld wat oar gedrach brekke yn 'e koade fan in oar dy't lang lyn skreaun is.

As wy it in stap fierder nimme, is it mooglik om te automatisearjen folle dingen. Mei ferskate CI / CD-ark, kinne jo testen opjaan om te rinnen as immen wizigingen nei in spesifike Git-tûke triuwt of foardat jo koade gearfoegje yn 'e produksjetûke. De ienfâldichste workflow soe wêze om Github Actions te brûken, haw ik in aparte fideo dy't it bewiist.

Wat moatte jo testen?

D'r binne ferskate mieningen oer hoe grut de saneamde "testdekking" moat wêze: besykje elke mooglike operaasje en saak op elke side, of behein it wurk ta de wichtichste dielen.

Yn feite is dit wêr't ik it iens is mei minsken dy't automatisearre testen beskuldigje dat se mear tiid nimme dan it feitlik foardiel leverje. Dit kin barre as jo tests skriuwe foar elk detail. Dat sei, it kin ferplicht wurde troch jo projekt: de wichtichste fraach is "wat is de priis fan potinsjele flater".

Mei oare wurden, jo moatte jo testepogings prioritearje troch de fraach te stellen "Wat soe barre as dizze koade mislearre?" As jo ​​betellingssysteem bugs hat, sil it direkt ynfloed hawwe op it bedriuw. Dus as de funksjonaliteit fan jo rollen / tagongsrjochten is brutsen, is dit in enoarm feiligensprobleem.

Ik fyn it leuk hoe't Matt Stauffer it op in konferinsje stelde: "Jo moatte earst dy dingen testen dy't, as se mislearje, jo fan jo baan ûntslein wurde." Dat is fansels in oerdriuwing, mar jo krije it idee: besykje earst de wichtige dingen. En dan oare funksjes, as jo tiid hawwe.

PEST: nij alternatyf foar PHPUnit

Alle boppesteande foarbylden binne basearre op Laravel pre testing arkdefinacht: PHPUnit . Mar yn 'e rin fan' e jierren binne oare ark yn it ekosysteem ferskynd en ien fan 'e lêste populêre is PEST . Makke troch offisjele Laravel-meiwurker Nuno Maduro , hat as doel de syntaksis te ferienfâldigjen, wêrtroch it skriuwen fan koade foar tests noch flugger makket.

Under de motorkap rint it su PHPUnit, as in ekstra laach, gewoan besykje wat foarôf werhelle dielen te minimalisearjendefinite fan de PHPUnit-koade.

Litte wy nei in foarbyld sjen. Unthâld de pre funksje test klassedefiniget yn Laravel? Ik sil dy ûnthâlde:

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

Witte jo hoe't deselde test der útsjen soe mei PEST?

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

Ja, ONE rigel koade en dat is it. Dat, it doel fan PEST is om de overhead fan:

  • It meitsjen fan klassen en metoaden foar alles;
  • Test case extension;
  • Troch aksjes op aparte rigels te setten: yn PEST kinne jo se oaninoar keatling.

Om in PEST-test yn Laravel te generearjen, moatte jo in ekstra flagge opjaan:

php artisan make:test HomepageTest --pest

Op dit stuit is PEST frij populêr ûnder Laravel-ûntwikkelders, mar it is jo persoanlike foarkar of jo dit ekstra ark brûke moatte en syn syntaksis leare, lykas ek in PHPUnit-notysje.

BlogInnovazione.it

Ynnovaasje nijsbrief
Mis it wichtichste nijs oer ynnovaasje net. Meld jo oan om se fia e-post te ûntfangen.

Recent articles

Ynnovative yntervinsje yn Augmented Reality, mei in Apple-sjogger by de Catania Polyclinic

In ophthalmoplasty-operaasje mei de Apple Vision Pro kommersjele werjouwer waard útfierd by de Catania Polyclinic ...

3 mei 2024

De foardielen fan kleurplaten foar bern - in wrâld fan magy foar alle leeftiden

It ûntwikkeljen fan fynmotoryske feardigens troch kleurjen taret bern op mear komplekse feardigens lykas skriuwen. Kleurje...

2 mei 2024

De takomst is hjir: hoe't de skipfeartsektor de wrâldekonomy revolúsjonearret

De marinesektor is in wiere wrâldwide ekonomyske macht, dy't navigearre is nei in merk fan 150 miljard ...

1 mei 2024

Utjouwers en OpenAI tekenje oerienkomsten om de stream fan ynformaasje te regeljen ferwurke troch Artificial Intelligence

Ofrûne moandei kundige de Financial Times in deal oan mei OpenAI. FT lisinsje har sjoernalistyk fan wrâldklasse ...

30 april 2024