Începeți testarea PHP cu Codeception

Publicat: 2022-03-11

Înainte de a trece la Codeception și PHP, ar trebui să acoperim elementele de bază și să începem prin a explica de ce avem nevoie de testare în aplicații în primul rând. Poate am putea finaliza un proiect fără să pierdem timpul cu teste, cel puțin de data aceasta?

Sigur, nu ai nevoie de teste pentru toate; de exemplu, când doriți să construiți încă o pagină de pornire. Probabil că nu aveți nevoie de teste atunci când proiectul dvs. conține pagini statice legate de un singur router.

Cu toate acestea, cu siguranță aveți nevoie de testare atunci când:

  • Echipa ta folosește BDD/TDD.
  • Repo-ul tău Git conține mai mult de câteva comite-uri.
  • Ești un profesionist adecvat, lucrează la un proiect serios.

Vă puteți scuza spunând că aveți deja un departament de testare dedicat, un grup de oameni care efectuează teste și scriu altele noi atunci când este nevoie. Dar, vă puteți imagina cât timp va dura remedierea erorilor după ce adăugați noi funcționalități la proiectul dvs.?

Ce rezolvă testarea?

În primul rând, să decidem ce fel de probleme pot fi rezolvate prin testare. Nu puteți scăpa de toate erorile dvs. prin testare, dar puteți descrie comportamentul așteptat în cazurile de testare. Erorile ar putea fi în cazurile dvs. de testare. Codul de spaghete rămâne cod de spaghete chiar și atunci când utilizați cazuri de testare.

Cu toate acestea, puteți fi sigur că codul dvs. va fi schimbat ulterior (prin remedierea erorilor sau adăugarea de noi funcții), astfel încât codul dvs. va fi în continuare fără erori descrise în test. În plus, chiar și testele bine scrise pot fi uneori folosite în documentație, deoarece acolo puteți vedea cum se derulează scenariile tipice și puteți verifica comportamentul așteptat. Putem spune că testarea este o investiție mică, dar crucială în viitor.

Deci, ce fel de teste putem folosi?

Testele unitare de bază de obicei nu sunt suficiente. Acestea trebuie să fie susținute de teste de integrare, funcționale și de acceptare.

Testele unitare de bază de obicei nu sunt suficiente. Acestea trebuie să fie susținute de teste de integrare, funcționale și de acceptare.
Tweet
  • Teste unitare: teste de nivel scăzut care verifică bucăți mici din codul tău - metodele clasei tale izolate de alt cod.
  • Testare de integrare: testele de integrare verifică o parte a aplicației dvs., ele pot conține mai multe clase sau metode, dar ar trebui să fie limitate la o singură caracteristică. Acest test ar trebui să verifice și modul în care diferitele clase interacționează.
  • Testare funcțională: Testează cereri specifice aplicației dvs.: răspunsul browserului, modificările bazei de date și așa mai departe.
  • Testarea de acceptare: În cele mai multe cazuri, testarea de acceptare înseamnă verificarea dacă aplicația îndeplinește toate cerințele clientului.

Pentru a clarifica, să presupunem că ilustrăm procesul cu ceva tangibil, cum ar fi o clădire. O clădire este compusă din blocuri mici care formează pereți. Fiecare cărămidă trebuie să îndeplinească cerințele specificate; trebuie să reziste la sarcina necesară, să aibă un volum și o formă specifice și așa mai departe. Acestea sunt teste unitare. Ideea testelor de integrare este de a verifica cât de strâns și de exact aderă cărămizile între ele, cum sunt integrate într-un anumit element al clădirii. Testele funcționale pot fi asemănate cu testele pe un singur perete al clădirii, pentru a verifica dacă interiorul este sau nu protejat de intemperii și dacă este sau nu posibil să se vadă soarele prin fereastră. Testarea de acceptare presupune testarea întregii clădiri ca un produs complet: deschide ușa, intră înăuntru, închide ușa, aprinde lumina, urcă la etajul doi și aruncă o privire spre grădina din afara clădirii.

Faceți cunoștință cu Codeception

Totuși, această împărțire este condiționată și uneori este dificil să reziste tentației de a amesteca diferite tipuri de teste.

Mulți dezvoltatori folosesc teste unitare și susțin că este suficient. Am fost unul dintre astfel de dezvoltatori; Am găsit că folosirea diferitelor sisteme pentru diferite tipuri de teste este prea dificilă și consumatoare de timp. Cu ceva timp în urmă, am decis să găsesc ceva mai util decât PHPUnit; Am vrut să fiu mai bun la testarea codului meu, dar nu am vrut să citesc și să învăț tone de documentație și să caut capcane. Așa am descoperit Codeception. La început, am fost sceptic, așa cum suntem adesea când vine vorba de ceva nou (acest proiect are cinci ani, așa că din punct de vedere tehnic, nu poate fi considerat „nou”), dar după ce ne-am jucat cu el câteva zile , am concluzionat Codeception este un sistem foarte util și puternic.

Deci, cum instalezi Codeception? Este cât se poate de simplu:

 $ composer require "codeception/codeception" $ php vendor/bin/codecept bootstrap

După instalare, veți găsi un nou folder denumit teste în proiectul dvs. și vor exista câteva subfoldere numite acceptare, funcțional și unit . Se pare că putem începe să ne scriem testele. Cool, dar ce urmează?

Acum, încercați să adăugați un test standard de acceptare Hello World.

 $ php vendor/bin/codecept generate:cept acceptance HelloWorld

Acum, obținem un fișier de test de acceptare tests/acceptance/HelloWorldCept.php, cu următorul conținut:

 <?php $I = new AcceptanceTester($scenario); $I->wantTo('perform actions and see result');

Variabila implicită, numită $I , nu este doar o literă; este un personaj. Ce conduce testele? Testerul, evident. Acest tester deschide pagina sau clasa site-ului dvs., face ceva cu ea și vă arată rezultatul final al acțiunilor sale. Veți vedea ce a funcționat și ce a mers prost. De aceea acest obiect este numit $I și de ce conține metode numite wantTo() , see() sau amOnPage() .

Deci, să ne gândim, așa cum ar face un tester, despre modalitățile de verificare a operabilității unei pagini. Prima abordare este să deschideți pagina și să căutați o expresie. Demonstrează că pagina este disponibilă vizitatorilor.

Acest lucru ar trebui să fie ușor:

 <?php $I->amOnPage('/'); $I->see('Welcome');

Putem folosi această comandă pentru a rula testele Codeception:

 $ php vendor/bin/codecept run

Vedem imediat că ceva nu este în regulă. La prima vedere, se pare că mesajul este prea lung și neclar, dar când ne uităm mai atent, totul devine evident.

Uau! Ceva n-a mers bine. Acesta este scopul testării. Verificați mesajul, identificați eroarea și învățați din greșelile dvs.

Uau! Ceva n-a mers bine. Acesta este scopul testării. Verificați mesajul, identificați eroarea și învățați din greșelile dvs.
Tweet

Am avut un test, Acceptation , și a detectat o eroare:

 Acceptance Tests (1) Perform actions and see result (HelloWorldCept) Error ---------- 1) Failed to perform actions and see result in HelloWorldCept (tests/acceptance/HelloWorldCept .php) [GuzzleHttp\Exception\ConnectException] cURL error 6: Could not resolve host: localhost (see http://curl.haxx.se/libcurl/c/libcurl-errors.html)

Acesta este vinovat: localhost nu este disponibil.

Și iată pașii scenariului testului nostru:

 1. $I->amOnPage("/")

Ok, să deschidem tests/acceptance.suite.yml și să schimbăm url: http://localhost/ cu ceva care este de fapt disponibil. În cazul meu, este gazda mea locală de testare, url: https://local.codeception-article.com/

Rulați din nou testul și acesta este ceea ce ar trebui să ajungeți:

 Acceptance Tests (1) --------------------------------------------------------------------------------------- Perform actions and result (HelloWorldCept) Ok

Ura! Primul nostru test de succes!

Desigur, amOnPage() nu este singura metodă de testare disponibilă, ci doar am evidențiat-o pentru exemplul nostru. Toate metodele de testare Codeception pot fi împărțite în următoarele grupuri:

  • Interacțiunea cu pagina: fillField() , selectOption() , submitForm() , click()
  • Afirmații. see() , dontSee() , seeElement() , seeInCurrentUrl() , seeCheckboxIsChecked() , seeInField() , seeLink() . La toate aceste metode puteți adăuga un sufix și îl puteți folosi atunci când aveți nevoie de o metodă care să nu întrerupă scenariul de testare atunci când ceva nu poate fi găsit.
  • Metode cookie: setCookie() , grabCookie() , seeCookie()
  • Comentariu și descrierea scenariilor de testare: amGoingTo() , wantTo() ) , expect( expect() . Utilizați aceste metode pentru a obține teste bine comentate și descrise, care vă vor ajuta să vă amintiți obiectivele testului.

Deci, dacă ar fi să testăm pagina de e-mail de resetare a parolei, am putea face acest lucru:

 <?php $I = new AcceptanceTester($scenario); $I->wantTo('Test forgotten password functionality'); $I->amOnPage('/forgotten') $I->see('Enter email'); $I->fillField('email', '[email protected]'); $I->click('Continue'); $I->expect('Reset password link not sent for incorrect email'); $I->see('Email is incorrect, try again'); $I->amGoingTo('Fill correct email and get link'); $I->see('Enter email'); $I->fillField('email', '[email protected]'); $I->click('Continue'); $I->expect('Reset password link sent for correct email'); $I->see('Please check your email for next instructions');

Se pare că acest lucru ar trebui să facă acest lucru, dar ce se întâmplă dacă există unele părți încărcate cu Ajax pe pagină? Putem testa o pagină ca asta? Răspunsul este că Codeception folosește PhpBrowser, bazat pe Symfony BrowserKit și Guzzle, în mod implicit. Este simplu, rapid și trebuie doar curl pentru ao folosi.

De asemenea, puteți utiliza Selenium și pagini de testare cu browsere reale. Da, va fi mai lent, dar veți putea testa și JavaScript.

Mai întâi, trebuie să instalați driverul Selenium, să schimbați acceptance.suite.yml și să reconstruiți clasa AcceptanceTester. După aceasta, puteți utiliza metodele wait() și waitForElement() . Și, mai interesant, vă veți putea economisi timp și resurse utilizând metodele saveSessionSnapshot() și loadSessionSnapshot() . Această metodă vă permite să stocați starea sesiunii și să începeți noi teste în sesiunile anterioare. Acest lucru este util în unele situații, de exemplu, în procesul de autorizare a testului.

Așadar, ajungem cu o abilitate simplă, dar puternică, de a testa multe funcții.

Testare funcțională

OK, este timpul să trecem la testarea funcțională.

 $ php vendor/bin/codecept generate:cept functional HelloWorld

Și asta obținem:

 <?php $I = new FunctionalTester($scenario); $I->amOnPage('/'); $I->see('Welcome');

Stai ce?

Nu, nu este o greșeală. Testele funcționale trebuie scrise în același mod ca și testele de integrare. Diferența este că testele funcționale interacționează direct cu aplicația dvs. Aceasta înseamnă că nu aveți nevoie de un server web pentru a rula testul funcțional și aveți mai multă capacitate de testare a diferitelor părți ale aplicației dvs.

Înseamnă că lipsește suportul pentru toate cadrele, dar lista de cadre acceptate este extinsă: Symfony, Silex, Phalcon, Yii, Zend Framework, Lumen, Laravel. Acest lucru ar trebui să fie suficient pentru majoritatea cazurilor și majoritatea dezvoltatorilor. Vă rugăm să consultați documentația modulelor Codeception pentru a obține o listă a funcțiilor disponibile și apoi doar porniți-o în functional.suite.yml .

Codeception acceptă cadre majore: Symfony, Silex, Phalcon, Yii, Zend Framework, Lumen, Laravel.

Codeception acceptă cadre majore: Symfony, Silex, Phalcon, Yii, Zend Framework, Lumen, Laravel.
Tweet

Înainte de a trece la testarea unitară, permiteți-mi să fac o mică digresiune. După cum probabil ați observat, am creat testele noastre cu cheia:

 $ php vendor/bin/codecept generate: cept acceptance HelloWorld

Aceasta nu este singura modalitate de a crea teste. Exista si teste cest . Diferența este că puteți structura mai multe scenarii asociate într-o singură clasă:

 $ php vendor/bin/codecept generate:cest acceptance HelloWorld <?php class HelloWorldCest { public function _before(AcceptanceTester $I) { $I->amOnPage('/forgotten') } public function _after(AcceptanceTester $I) { } // tests public function testEmailField(AcceptanceTester $I) { $I->see('Enter email'); } public function testIncorrectEmail(AcceptanceTester $I) { $I->fillField('email', '[email protected]'); $I->click('Continue'); $I->see('Email is incorrect, try again'); } public function testCorrectEmail(AcceptanceTester $I) { $I->fillField('email', '[email protected]'); $I->click('Continue'); $I->see('Please check your email for next instructions'); } }

În acest exemplu, metodele _before() și _after() sunt executate înainte și după fiecare test. O instanță a clasei AcceptanceTester este transmisă fiecărui test, așa că o puteți utiliza în același mod ca în testele cest. Acest stil de teste poate fi util în anumite situații, așa că merită reținut.

Testarea unitară

E timpul pentru niște teste unitare.

Codeception se bazează pe PHPUnit, așa că puteți folosi teste scrise pentru PHPUnit. Pentru a adăuga noi teste PHPUnit, utilizați următoarea abordare:

 $ php vendor/bin/codecept generate:phpunit unit HelloWorld

Sau pur și simplu moșteniți testele pe \PHPUnit_Framework_TestCase .

Dar dacă doriți ceva mai mult, ar trebui să încercați testele unitare ale Codeception:

 $ php vendor/bin/codecept generate:test unit HelloWorld <?php class HelloWorldTest extends \Codeception\TestCase\Test { /** * @var \UnitTester */ protected $tester; protected function _before() { } protected function _after() { } // tests public function testUserSave() { $user = User::find(1); $user->setEmail('[email protected]'); $user->save(); $user = User::find(1); $this->assertEquals('[email protected]', $user->getEmail()); } }

Nimic neobișnuit deocamdată. Metodele _before() și _after() sunt analoge setUp( setUp() și tearDown() și vor rula înainte și după fiecare test.

Principalul avantaj al acestui test este în capacitatea sa de a vă extinde procesul de testare prin includerea modulelor care pot fi activate în unit.suite.yml :

  • Acces la memcache și baze de date pentru a urmări modificările (sunt acceptate MySQL, SQLite, PostgreSQL, MongoDB)
  • Testarea aplicațiilor REST/SOAP
  • Cozile

Fiecare modul are propriile caracteristici, așa că cel mai bine este să verificați documentația și să colectați informațiile necesare pentru fiecare modul înainte de a trece la testele reale.

În plus, puteți utiliza pachetul Codeception/Specify (care trebuie adăugat la composer.json ) și puteți scrie o descriere astfel:

 <?php class HelloWorldTest extends \Codeception\TestCase\Test { use \Codeception\Specify; private $user; protected function _before() { $this->user = User::find(1); } public function testUserEmailSave() { $this->specify("email can be stored", function() { $this->user->setEmail('[email protected]'); $this->user->save(); $user = User::find(1); $this->assertEquals('[email protected]', $user->getEmail()); }); } }

Codul PHP din interiorul acestor funcții de închidere este izolat, așa că modificările din interior nu vor afecta restul codului. Descrierile vă vor ajuta să faceți testul mai ușor de citit și să ușurați identificarea testelor nereușite.

Ca suplimentar opțional, puteți utiliza pachetul Codeception\Verify pentru sintaxa asemănătoare BDD:

 <?php public function testUserEmailSave() { verify($map->getEmail())->equals('[email protected]'); }

Și, desigur, puteți folosi stub-uri:

 <?php public function testUserEmailSave() { $user = Stub::make('User', ['getEmail' => '[email protected]']); $this->assertEquals('[email protected]', $user->getEmail()); }

Verdict: Codecepția economisește timp și efort

Deci, la ce ar trebui să vă așteptați de la Codeception? Pentru cine este? Există avertismente?

Codeception poate fi folosit de dezvoltatori cu niveluri de competență PHP foarte diferite și echipe de toate dimensiunile.

Codeception poate fi folosit de dezvoltatori cu niveluri de competență PHP foarte diferite și echipe de toate dimensiunile.
Tweet

În opinia mea, acest cadru de testare este potrivit pentru tot felul de echipe diferite: mari și mici, începători și profesioniști PHP înrădăcinați, cei care folosesc un cadru popular și cei care nu folosesc niciun cadru.

În orice caz, totul se rezumă la asta: Codeception este gata pentru prime time.

Este un cadru matur și bine documentat, care poate fi extins cu ușurință prin numeroase module. Codeception este modernă, dar bazată pe PHPUnit testat în timp, care ar trebui să liniștească dezvoltatorii care nu vor să experimenteze prea mult.

Funcționează bine, ceea ce înseamnă că este rapid și nu necesită prea mult timp și efort. Mai bine, este relativ ușor de stăpânit, iar documentația abundentă ar trebui să ajute un proces de învățare fără probleme.

Codeception este, de asemenea, ușor de instalat și configurat, dar se mândrește cu o mulțime de opțiuni avansate. În timp ce majoritatea utilizatorilor nu vor avea nevoie de toate (sau într-adevăr, de majoritatea), totul depinde de ceea ce intenționați să faceți cu ele. Puteți începe cu elementele de bază, iar funcțiile suplimentare vă vor fi utile mai devreme sau mai târziu.

Înrudit : Cod PHP Buggy: Cele mai frecvente 10 greșeli pe care le fac dezvoltatorii PHP