Skip to content

PHPUnit și TDD: cum scrii teste unitare în PHP

  • SEOcluj
  • PHP

Testarea automată a codului este o practică esențială în dezvoltarea software modernă, iar PHPUnit este standardul de facto pentru testarea în PHP. Combinat cu metodologia TDD (Test-Driven Development), PHPUnit te ajută să scrii cod mai robust, mai ușor de menținut și cu mai puține bug-uri.

Acest ghid explorează cum să implementezi testarea unitară efectiv în proiectele tale PHP.

Ce este TDD și de ce să îl adopți

Test-Driven Development este o metodologie de dezvoltare în care testele sunt scrise înainte de codul de producție. Ciclul TDD clasic urmează trei pași: Red (scrie un test care eșuează), Green (scrie codul minim care face testul să treacă), Refactor (îmbunătățește codul fără a schimba comportamentul).

Această abordare poate părea contra-intuitivă la început, dar aduce beneficii semnificative în calitatea codului și designul arhitecturii. Dacă ești nou în PHP, îți recomandăm să citești mai întâi ghidul despre programare PHP orientată pe obiecte.

Avantajele testării automate

Testele automate oferă un net de siguranță care îți permite să refactorizezi și să adaugi funcționalități noi fără teama de a strica ce funcționează deja. Documentează comportamentul așteptat al codului mai precis decât orice documentație scrisă.

Forțează un design mai bun al codului, deoarece codul greu de testat este de obicei și greu de menținut. Reduc semnificativ timpul petrecut în debugging, deoarece eșecurile testelor indică exact unde s-a introdus o regresie.

Consultă și ghidul despre securizarea aplicațiilor PHP pentru practici complementare de calitate a codului.

Tipuri de teste: unitare, integrare, funcționale

Testele unitare testează o singură unitate de cod (de obicei o metodă sau o funcție) în izolare față de dependențele externe. Testele de integrare verifică că mai multe componente funcționează corect împreună.

Testele funcționale (sau end-to-end) testează aplicația din perspectiva utilizatorului. PHPUnit este optimizat pentru testele unitare și de integrare.

Piramida de testare recomandă o proporție mare de teste unitare, un număr moderat de teste de integrare și puține teste end-to-end.

Instalarea și configurarea PHPUnit

PHPUnit se instalează ușor prin Composer și se configurează printr-un fișier XML. Înțelegerea configurației de bază este primul pas pentru a începe testarea.

Instalare prin Composer

PHPUnit se adaugă ca dependență de development: composer require --dev phpunit/phpunit ^11. Versiunea 11 este compatibilă cu PHP 8.2 și 8.3.

Dacă lucrezi cu Laravel, framework-ul include PHPUnit implicit și are wrapper-ul Artisan php artisan test care adaugă funcționalități suplimentare. Poți citi mai multe despre PHP 8 în articolul nostru despre noile funcționalități PHP 8.

Despre Composer și managementul dependențelor, consultă ghidul nostru despre Composer.

Configurarea phpunit.xml

Fișierul phpunit.xml (sau phpunit.xml.dist) definește configurația suites de teste, directoarele unde se găsesc testele, variabilele de mediu pentru testare și rapoartele generate. O configurare tipică definește o suită pentru teste unitare (în directorul tests/Unit) și una pentru teste de integrare (tests/Feature).

Folosirea unui fișier .env.testing separat pentru configurarea bazei de date de test și a altor servicii externe este o practică recomandată.

Structura unui test PHPUnit

Fiecare clasă de test extinde PHPUnit Framework TestCase și conține metode care încep cu test sau sunt adnotate cu @test. setUp() rulează înainte de fiecare test și este locul pentru inițializare. tearDown() rulează după fiecare test pentru curățare. Metodele de assert (assertEquals, assertTrue, assertInstanceOf etc.) verifică că rezultatele sunt cele așteptate.

Tehnici avansate de testare cu PHPUnit

Odată stăpânite bazele, există tehnici avansate care fac testele mai puternice și mai flexibile.

Mock objects și Stubs

Mock objects și Stubs sunt obiecte care simulează comportamentul dependențelor externe. Un stub înlocuiește o dependență cu o implementare simplificată care returnează valori predefinite.

Un mock merge mai departe și verifică că anumite metode au fost apelate cu anumiți parametri. PHPUnit are un sistem built-in de creare a mock-urilor cu createMock() și getMockBuilder().

Utilizarea mock-urilor permite testarea codului în izolare, fără a depinde de baze de date, API-uri externe sau alte servicii. Această abordare este esențială în Laravel – citește mai mult în ghidul despre Eloquent ORM în Laravel.

Data Providers

Data Providers permit rularea aceluiași test cu seturi multiple de date de intrare. Prin atributul #[DataProvider] sau adnotarea @dataProvider, poți asocia o metodă care returnează un array de array-uri cu seturi de date.

PHPUnit va rula testul pentru fiecare set de date separat, raportând eșecurile individual. Aceasta elimină duplicarea codului când vrei să testezi aceeași logică cu valori diferite.

Acoperirea codului (Code Coverage)

PHPUnit poate genera rapoarte de acoperire a codului care arată ce procent din codul de producție este executat de teste. Acoperirea se poate genera în format HTML (pentru vizualizare în browser), XML sau Clover (pentru integrare CI).

Un procent ridicat de acoperire nu garantează calitatea testelor, dar este un indicator util. Xdebug sau PCOV trebuie instalate pentru generarea rapoartelor de acoperire.

Urmărirea acoperirii codului în timp poate identifica zonele din aplicație care necesită mai multă atenție la testare.

Integrarea PHPUnit în fluxul de lucru

Pentru a obține maximum de valoare din testare, aceasta trebuie integrată în procesul de dezvoltare și deployment.

Rularea testelor în CI/CD

Rularea automată a testelor la fiecare push sau pull request este o practică esențială. GitHub Actions, GitLab CI, CircleCI sau Jenkins pot fi configurate să ruleze PHPUnit și să blocheze merge-ul dacă testele eșuează.

Această practică previne introducerea de regresiumi în codul de producție. Combinarea cu analiza statică (PHPStan, Psalm) și lintere de cod (PHP CS Fixer) creează un pipeline de calitate a codului robust.

Testarea în proiecte Laravel

Laravel oferă o suită de facilități suplimentare pentru testare peste PHPUnit de bază. RefreshDatabase și DatabaseMigrations gestionează starea bazei de date între teste.

Http::fake() permite simularea request-urilor HTTP externe. Facades-urile Laravel pot fi ușor mock-uite cu metodele lor built-in.

Factories și Seeders facilitează crearea datelor de test. Dacă lucrezi cu Laravel, citește și ghidul despre introducere în Laravel și cel despre autentificarea în aplicații Laravel.

PHPUnit și TDD transformă modul în care scrii și gândești codul. Investiția inițială în scriere de teste se recuperează rapid prin reducerea bug-urilor în producție, refactorizare mai sigură și o mai bună înțelegere a cerințelor.

Adoptarea graduală, începând cu testele pentru codul nou, este calea practică spre o bază de cod bine testată.

Back To Top