Artikuj

Mësoni si të bëni teste në Laravel me shembuj të thjeshtë, duke përdorur PHPUnit dhe PEST

Kur bëhet fjalë për testet e automatizuara ose testet e njësive, në çdo gjuhë programimi, ekzistojnë dy mendime të kundërta:

  • Humbje kohe
  • Ju nuk mund të bëni pa të

Pra, me këtë artikull ne do të përpiqemi të bindim të parën, veçanërisht duke demonstruar se sa e lehtë është të filloni me testimin e automatizuar në Laravel.

Së pari le të flasim për "pse" dhe më pas le të shohim disa shembuj se si.

Pse kemi nevojë për testim të automatizuar

Testet e automatizuara ekzekutojnë pjesë të kodit dhe raportojnë çdo gabim. Kjo është mënyra më e thjeshtë për t'i përshkruar ato. Imagjinoni të hapni një veçori të re në një aplikacion, dhe më pas një ndihmës personal robotik do të shkonte dhe do të testonte manualisht funksionin e ri, duke testuar gjithashtu nëse kodi i ri nuk thyente ndonjë nga veçoritë e vjetra.

Ky është avantazhi kryesor: ritestimi i të gjitha veçorive automatikisht. Kjo mund të duket si punë shtesë, por nëse nuk i thoni "robotit" ta bëjë atë, ne duhet ta bëjmë atë me dorë, apo jo? 

Ose veçoritë e reja mund të lëshohen pa testuar nëse funksionojnë, duke shpresuar që përdoruesit të raportojnë gabime.

Testet e automatizuara mund të na japin disa përparësi:

  • Kurseni kohën e testimit manual;
  • Ato ju lejojnë të kurseni kohë si në funksionin e ri të zbatuar ashtu edhe në funksionet e konsoliduara duke shmangur regresionin;
  • Shumëzojeni këtë përfitim me të gjitha veçoritë e reja dhe të gjitha veçoritë e implementuara tashmë;
  • Tre pikat e mëparshme vlejnë për çdo version të ri;
  • ...

Përpiquni të imagjinoni aplikacionin tuaj në një ose dy vjet, me zhvillues të rinj në ekip që nuk e dinë kodin e shkruar në vitet e mëparshme, madje as si ta testojnë atë. 

Testet tona të para të automatizuara

Për të kryer të parën testimi i automatizuar në Laravel, nuk keni nevojë të shkruani asnjë kod. Po, e lexuat mirë. Gjithçka tashmë është konfiguruar dhe përgatitur në para-instalimindefinite of Laravel, duke përfshirë shembullin e parë themelor.

Mund të provoni të instaloni një projekt Laravel dhe të kryeni testet e para menjëherë:

laravel new project
cd project
php artisan test

Ky duhet të jetë rezultati në konsolën tuaj:

Nëse i hedhim një sy paradefinata e Laravel /tests, kemi dy skedarë:

teste/Feature/ExampleTest.php:

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

Ju nuk keni nevojë të dini ndonjë sintaksë për të kuptuar se çfarë po ndodh këtu: ngarkoni faqen kryesore dhe kontrolloni nëse kodi i statusit HTTP eshte "200 OK".

Gjithashtu i njohur si emri i metodës test_the_application_returns_a_successful_response() bëhet tekst i lexueshëm kur shikoni rezultatet e testit, thjesht duke zëvendësuar simbolin e nënvizuar me një hapësirë.

teste/Njësi/ShembullTest.php:

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

Duket pak e kotë, duke kontrolluar nëse kjo është e vërtetë? 

Ne do të flasim konkretisht për testet e njësisë pak më vonë. Tani për tani, ju duhet të kuptoni se çfarë ndodh në përgjithësi në çdo test.

  • Çdo skedar testimi në dosje /tests është një klasë PHP që zgjeron TestCase të PHPNjësia
  • Brenda çdo klase, ju mund të krijoni metoda të shumta, zakonisht një metodë për të provuar një situatë
  • Brenda secilës metodë ekzistojnë tre veprime: përgatitja e situatës, pastaj veprimi dhe më pas verifikimi (pohimi) nëse rezultati është ashtu siç pritej.

Strukturisht, kjo është gjithçka që duhet të dini, gjithçka tjetër varet nga gjërat ekzakte që dëshironi të testoni.

Për të gjeneruar një klasë testi boshe, thjesht ekzekutoni këtë komandë:

php artisan make:test HomepageTest

Skedari është krijuar 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);
    }
}

Tani le të shohim se çfarë ndodh nëse një kod testimi dështon në Laravel

Le të shohim tani se çfarë ndodh nëse pohimet e testit nuk japin rezultatin e pritur.

Le t'i ndryshojmë shembujt e testeve në këtë:

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

Dhe tani, nëse ekzekutojmë komandën php artisan test përsëri:

 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

Janë dy teste të dështuara, të shënuara si FAIL, me shpjegime më poshtë dhe shigjeta që tregojnë linjën e saktë të testeve që dështuan. Gabimet tregohen në këtë mënyrë.

Shembull: Testimi i kodit të formularit të regjistrimit në Laravel

Supozoni se kemi një formular dhe duhet të testojmë raste të ndryshme: kontrollojmë nëse dështon me të dhëna të pavlefshme, kontrollojmë nëse ka sukses me hyrjen e saktë, etj.

Kompleti zyrtar fillestar nga Laravel Breeze përfshin i testimi i funksionalitetit brenda tij. Le të shohim disa shembuj nga atje:

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

Këtu kemi dy teste në një klasë, pasi që të dyja lidhen me formularin e regjistrimit: njëri kontrollon nëse formulari është ngarkuar saktë dhe një tjetër kontrollon nëse paraqitja funksionon mirë.

Le të njihemi me dy metoda të tjera për verifikimin e rezultatit, dy pohime të tjera: $this->assertAuthenticated()$response->assertRedirect(). Ju mund të kontrolloni të gjitha pohimet e disponueshme në dokumentacionin zyrtar të PHPNjësia e Përgjigja e Laravel . Vini re se disa pohime të përgjithshme ndodhin mbi këtë temë $this, ndërsa të tjerët kontrollojnë specifikën $responsenga thirrja e rrugës.

Një tjetër gjë e rëndësishme është use RefreshDatabase;deklaratë, me goditje, të futur mbi klasë. Është e nevojshme kur veprimet e testimit mund të ndikojnë në bazën e të dhënave, si në këtë shembull, logging shton një hyrje të re në userstabela e bazës së të dhënave. Për këtë, ju duhet të krijoni një bazë të dhënash të veçantë testimi e cila do të përditësohet php artisan migrate:freshsa herë që kryhen testet.

Ju keni dy opsione: krijoni fizikisht një bazë të dhënash të veçantë ose përdorni një bazë të dhënash SQLite në memorie. Të dyja janë konfiguruar në skedar phpunit.xmldhënë si parazgjedhjedefinita me Laravel. Konkretisht, ju duhet kjo pjesë:

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

Shihni DB_CONNECTIONDB_DATABASEcilat komentohen? Nëse keni SQLite në serverin tuaj, veprimi më i thjeshtë është thjesht të çkomentoni ato rreshta dhe testet tuaja do të ekzekutohen kundër asaj baze të dhënash në memorie.

Në këtë test themi se përdoruesi është vërtetuar me sukses dhe është ridrejtuar në faqen e duhur kryesore, por mund të testojmë edhe të dhënat aktuale në bazën e të dhënave.

Përveç këtij kodi:

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

Mund të përdorim edhe pohimet e testit të bazës së të dhënave dhe bëni diçka të tillë:

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

Shembull i faqes së hyrjes

Le të shohim tani një shembull tjetër të një faqe identifikimi me 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();
    }
}

Bëhet fjalë për formularin e hyrjes. Logjika është e ngjashme me regjistrimin, apo jo? Por tre metoda në vend të dy, kështu që ky është një shembull i testimit të skenarëve të mirë dhe të keq. Pra, logjika e përbashkët është që duhet të testoni të dyja rastet: kur gjërat shkojnë mirë dhe kur dështojnë.

Buletini i inovacionit
Mos humbisni lajmet më të rëndësishme mbi inovacionin. Regjistrohuni për t'i marrë ato me email.

Gjithashtu, ajo që shihni në këtë test është përdorimi i Fabrikat e bazave të të dhënave : Laravel krijon përdorues të rremë ( përsëri, në bazën e të dhënave të përditësuar të testit ) dhe më pas përpiqet të identifikohet, me kredenciale të sakta ose të pasakta.

Edhe një herë, Laravel gjeneron para fabrikësdefinita me të dhëna të rreme për të Usermodel, jashtë kutisë.

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

E shihni, sa gjëra janë përgatitur nga vetë Laravel, kështu që a do të ishte e lehtë për ne të fillonim testimin?

Pra, nëse ekzekutojmë php artisan testPas instalimit të Laravel Breeze, duhet të shohim diçka të tillë:

 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

Testet funksionale krahasuar me testet e njësive dhe të tjera

Ju keni parë nëndosjet tests/Feature e tests/Unit ?. 

Cili është ndryshimi midis tyre? 

Globalisht, jashtë ekosistemit Laravel/PHP, ekzistojnë disa lloje të testimit të automatizuar. Ju mund të gjeni terma si:

  • Testet e njësisë
  • Testimi i veçorive
  • Testet e integrimit
  • Testet funksionale
  • Testimi nga fundi në fund
  • Testet e pranimit
  • Testet e tymit
  • etj.

Duket e ndërlikuar dhe ndryshimet aktuale midis këtyre llojeve të testeve ndonjëherë janë të paqarta. Kjo është arsyeja pse Laravel i ka thjeshtuar të gjitha këto terma konfuze dhe i ka grupuar në dy: njësi/veçori.

E thënë thjesht, testet e veçorive përpiqen të ekzekutojnë funksionalitetin aktual të aplikacioneve tuaja: merrni URL-në, telefononi API-në, imitoni sjelljen e saktë si plotësimi i formularit. Testet e veçorive zakonisht kryejnë të njëjtat operacione ose të ngjashme siç do të bënte çdo përdorues i projektit, me dorë, në jetën reale.

Testet e njësive kanë dy kuptime. Në përgjithësi, mund të zbuloni se çdo test i automatizuar quhet "testim i njësisë" dhe i gjithë procesi mund të quhet "testim i njësisë". Por në kontekstin e funksionalitetit kundrejt njësisë, ky proces ka të bëjë me testimin e një njësie specifike jopublike të kodit, në izolim. Për shembull, ju keni një klasë Laravel me një metodë që llogarit diçka, si çmimi total i porosisë me parametra. Prandaj, testi i njësisë do të deklaronte nëse rezultatet e sakta janë kthyer nga ajo metodë (njësia e kodit), me parametra të ndryshëm.

Për të gjeneruar një test njësie, duhet të shtoni një flamur:

php artisan make:test OrderPriceTest --unit

Kodi i gjeneruar është i njëjtë me testin para njësisëdefiSistemi Laravel:

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

Siç mund ta shihni, nuk ekziston RefreshDatabase, dhe kjo është një nga defiPërkufizimet më të zakonshme të testit të njësisë: nuk prek bazën e të dhënave, funksionon si një "kuti e zezë", e izoluar nga aplikacioni që funksionon.

Duke u përpjekur të imitojmë shembullin që përmenda më parë, le të imagjinojmë se kemi një klasë shërbimi OrderPrice.

app/Services/OrderPriceService.php:

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

Pastaj, testi i njësisë mund të duket diçka si kjo:

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
}

Në përvojën time personale me projektet Laravel, shumica dërrmuese e testeve janë teste të veçorive, jo teste të njësisë. Së pari, duhet të provoni nëse aplikacioni juaj funksionon, si do ta përdornin njerëzit e vërtetë.

Më pas, nëse keni llogaritje ose logjikë të veçantë, mundeni definire si njësi, me parametra, mund të krijoni teste njësie posaçërisht për këtë.

Ndonjëherë, shkrimi i testeve kërkon modifikimin e vetë kodit dhe rifaktorimin e tij për ta bërë atë më "të testueshëm": ndarjen e njësive në klasa ose metoda të veçanta.

Kur/si të kryhen testet?

Cili është përdorimi aktual i kësaj php artisan test, kur duhet ta ekzekutoni?

Ka qasje të ndryshme, në varësi të rrjedhës së punës së biznesit tuaj, por në përgjithësi duhet të siguroheni që të gjitha testet të jenë "të gjelbra" (d.m.th. pa gabime) përpara se të shtyni ndryshimet e kodit përfundimtar në depo.

Pastaj, ju punoni në nivel lokal në detyrën tuaj dhe kur mendoni se keni mbaruar, kryeni disa teste për t'u siguruar që nuk keni prishur asgjë. Mbani mend, kodi juaj mund të shkaktojë gabime jo vetëm në logjikën tuaj, por gjithashtu të prishë pa dashje disa sjellje të tjera në kodin e dikujt tjetër të shkruar shumë kohë më parë.

Nëse e bëjmë një hap më tej, është e mundur të automatizohet i shkrirë gjërat. Me mjete të ndryshme CI/CD, mund të specifikoni testet që do të ekzekutohen sa herë që dikush shtyn ndryshime në një degë specifike Git ose përpara se të bashkojë kodin në degën e prodhimit. Rrjedha më e thjeshtë e punës do të ishte përdorimi i Github Actions, unë kam një video të veçantë që e vërteton.

Çfarë duhet të testoni?

Ka mendime të ndryshme se sa i madh duhet të jetë i ashtuquajturi "mbulim testimi": provoni çdo operacion dhe rast të mundshëm në çdo faqe, ose kufizoni punën në pjesët më të rëndësishme.

Në fakt, kjo është ajo ku unë pajtohem me njerëzit që akuzojnë testimin e automatizuar se kërkon më shumë kohë sesa sigurimin e përfitimit aktual. Kjo mund të ndodhë nëse shkruani teste për çdo detaj të vetëm. Thënë kështu, mund të kërkohet nga projekti juaj: pyetja kryesore është "sa është çmimi i gabimit të mundshëm".

Me fjalë të tjera, ju duhet t'i jepni përparësi përpjekjeve tuaja të testimit duke bërë pyetjen "Çfarë do të ndodhte nëse ky kod dështon?" Nëse sistemi juaj i pagesave ka defekte, kjo do të ndikojë drejtpërdrejt në biznes. Pra, nëse funksionaliteti i roleve/lejeve tuaja është i prishur, kjo është një çështje e madhe sigurie.

Më pëlqen mënyra se si Matt Stauffer e shprehu atë në një konferencë: "Së pari duhet të provoni ato gjëra që, nëse dështojnë, do t'ju largonin nga puna". Sigurisht që është një ekzagjerim, por e kuptoni idenë: provoni së pari gjërat e rëndësishme. Dhe pastaj veçori të tjera, nëse keni kohë.

PEST: alternativë e re për PHPUnit

Të gjithë shembujt e mësipërm bazohen në mjetin para testimit të Laraveldefinata: PHPNjësia . Por me kalimin e viteve janë shfaqur mjete të tjera në ekosistem dhe një nga më të fundit të njohura është DEMTARI . Krijuar nga punonjësi zyrtar i Laravel Nuno Maduro , synon të thjeshtojë sintaksën, duke e bërë edhe më të shpejtë shkrimin e kodit për teste.

Nën kapuç, ajo shkon su PHPUnit, si një shtresë shtesë, thjesht përpiqet të minimizojë disa pjesë të parapërsërituradefinite e kodit PHPUnit.

Le të shohim një shembull. Mbani mend klasën e testit para veçorivedefie vendosur në Laravel? Unë do t'ju kujtoj:

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

A e dini se si do të dukej i njëjti test me PEST?

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

Po, NJË rresht kodi dhe kaq. Pra, qëllimi i PEST është të heqë shpenzimet e përgjithshme të:

  • Krijimi i klasave dhe metodave për gjithçka;
  • Zgjatja e rastit të testimit;
  • Duke vendosur veprime në linja të veçanta: në PEST ju mund t'i lidhni ato me zinxhir.

Për të gjeneruar një test PEST në Laravel, duhet të specifikoni një flamur shtesë:

php artisan make:test HomepageTest --pest

Që nga momenti i shkrimit, PEST është mjaft i popullarizuar në mesin e zhvilluesve të Laravel, por është preferenca juaj personale nëse do të përdorni këtë mjet shtesë dhe të mësoni sintaksën e tij, si dhe një shënim PHPUnit.

BlogInnovazione.it

Buletini i inovacionit
Mos humbisni lajmet më të rëndësishme mbi inovacionin. Regjistrohuni për t'i marrë ato me email.

Artikujt e fundit

Botuesit dhe OpenAI nënshkruajnë marrëveshje për të rregulluar rrjedhën e informacionit të përpunuar nga Inteligjenca Artificiale

Të hënën e kaluar, Financial Times njoftoi një marrëveshje me OpenAI. FT licencon gazetarinë e saj të klasit botëror…

30 Prill 2024

Pagesat në internet: Ja se si shërbimet e transmetimit ju bëjnë të paguani përgjithmonë

Miliona njerëz paguajnë për shërbimet e transmetimit, duke paguar tarifat mujore të abonimit. Është e zakonshme që ju…

29 Prill 2024

Veeam përmban mbështetjen më të plotë për ransomware, nga mbrojtja te përgjigja dhe rikuperimi

Coveware nga Veeam do të vazhdojë të ofrojë shërbime të reagimit ndaj incidenteve të zhvatjes kibernetike. Coveware do të ofrojë aftësi mjeko-ligjore dhe riparimi…

23 Prill 2024

Revolucioni i gjelbër dhe dixhital: Si mirëmbajtja parashikuese po transformon industrinë e naftës dhe gazit

Mirëmbajtja parashikuese po revolucionon sektorin e naftës dhe gazit, me një qasje inovative dhe proaktive për menaxhimin e impiantit.…

22 Prill 2024