Avvia i tuoi test PHP con Codeception
Pubblicato: 2022-03-11Prima di passare a Codeception e PHP, dovremmo coprire le basi e iniziare spiegando perché in primo luogo abbiamo bisogno di test nelle applicazioni. Forse potremmo portare a termine un progetto senza perdere tempo in test, almeno questa volta?
Certo, non hai bisogno di test per tutto; per esempio, quando vuoi costruire un'altra home page. Probabilmente non hai bisogno di test quando il tuo progetto contiene pagine statiche collegate da un router.
Tuttavia, hai sicuramente bisogno di test quando:
- Il tuo team usa BDD/TDD.
- Il tuo repository Git contiene più di un paio di commit.
- Sei un vero professionista, che lavora su un progetto serio.
Puoi scusarti dicendo che hai già un reparto test dedicato, un gruppo di persone che conduce test e ne scrive di nuovi quando necessario. Ma puoi immaginare quanto tempo impiegherà la correzione dei bug dopo aver aggiunto nuove funzionalità al tuo progetto?
Cosa risolve il test?
Innanzitutto, decidiamo che tipo di problemi possono essere risolti attraverso i test. Non puoi eliminare tutti i tuoi errori con i test, ma puoi descrivere il comportamento previsto nei casi di test. Gli errori potrebbero essere all'interno dei tuoi casi di test. Il codice spaghetti rimane il codice spaghetti anche quando si utilizzano casi di test.
Tuttavia, puoi essere certo che il tuo codice verrà modificato in seguito (correggendo errori o aggiungendo nuove funzionalità), quindi il tuo codice sarà comunque privo di errori descritti nel test. Inoltre, anche test ben scritti possono talvolta essere utilizzati nella documentazione perché lì puoi vedere come si svolgono scenari tipici e verificare il comportamento previsto. Possiamo dire che il test è un piccolo ma cruciale investimento per il futuro.
Quindi che tipo di test possiamo impiegare?
- Test unitari: test di basso livello che controllano piccoli pezzi del tuo codice: i metodi della tua classe isolati da altro codice.
- Test di integrazione: i test di integrazione controllano una parte dell'applicazione, possono contenere diverse classi o metodi, ma dovrebbero essere limitati a una funzionalità. Questo test dovrebbe anche verificare come interagiscono classi diverse.
- Test funzionale: verifica richieste specifiche alla tua applicazione: risposta del browser, modifiche al database e così via.
- Test di accettazione: nella maggior parte dei casi, test di accettazione significa verificare se l'applicazione soddisfa tutti i requisiti del cliente.
Per chiarire, diciamo di illustrare il processo con qualcosa di tangibile, come un edificio. Un edificio è composto da piccoli blocchi che formano muri. Ogni mattone deve soddisfare requisiti specifici; deve sopportare il carico richiesto, avere un volume e una forma specifici e così via. Questi sono test unitari. L'idea dei test integrativi è di verificare quanto strettamente e accuratamente i mattoni aderiscano l'uno all'altro, come siano integrati in un determinato elemento dell'edificio. Le prove funzionali possono essere paragonate a prove su una singola parete dell'edificio, per verificare se l'interno è protetto o meno dalle intemperie e se è possibile o meno vedere il sole attraverso la finestra. Il test di accettazione prevede il collaudo dell'intero edificio come prodotto completo: aprire la porta, entrare, chiudere la porta, accendere la luce, salire al secondo piano e dare un'occhiata al giardino esterno dell'edificio.
Incontra Codeception
Tuttavia, questa divisione è condizionale ea volte è difficile resistere alla tentazione di mischiare diversi tipi di test.
Molti sviluppatori usano unit test e affermano che è sufficiente. Ero uno di questi sviluppatori; Ho trovato l'utilizzo di diversi sistemi per diversi tipi di test troppo difficile e dispendioso in termini di tempo. Tempo fa ho deciso di trovare qualcosa di più utile di PHPUnit; Volevo essere più bravo a testare il mio codice, ma non volevo leggere e imparare tonnellate di documentazione e cercare insidie. È così che ho scoperto Codeception. All'inizio ero scettico, come spesso accade quando si tratta di qualcosa di nuovo (questo progetto ha cinque anni, quindi tecnicamente non può essere considerato "nuovo"), ma dopo averci giocato per un paio di giorni , ho concluso Codeception è un sistema molto utile e potente.
Quindi come si installa Codeception? È così semplice:
$ composer require "codeception/codeception" $ php vendor/bin/codecept bootstrap
Dopo l'installazione, troverai una nuova cartella denominata test nel tuo progetto e ci saranno alcune sottocartelle denominate accettazione, funzionale e unità . Sembra che possiamo iniziare a scrivere i nostri test. Fantastico, ma cosa c'è dopo?
Ora, prova ad aggiungere un test Hello World di accettazione standard.
$ php vendor/bin/codecept generate:cept acceptance HelloWorld
Ora, otteniamo un file di test di accettazione test/acceptance/HelloWorldCept.php, con il seguente contenuto:
<?php $I = new AcceptanceTester($scenario); $I->wantTo('perform actions and see result');
La variabile predefinita, denominata $I
, non è solo una lettera; è un personaggio. Cosa conduce i test? Il tester, ovviamente. Questo tester apre la pagina o la classe del tuo sito web, fa qualcosa con esso e ti mostra il risultato finale delle sue azioni. Vedrai cosa ha funzionato e cosa è andato storto. Ecco perché questo oggetto si chiama $I
e perché contiene metodi chiamati wantTo()
, see()
o amOnPage()
.
Quindi, pensiamo come farebbe un tester sui modi per controllare l'operabilità di una pagina. Il primo approccio è aprire la pagina e cercare una frase. Dimostra che la pagina è disponibile per i visitatori.
Questo dovrebbe essere facile:
<?php $I->amOnPage('/'); $I->see('Welcome');
Possiamo usare questo comando per eseguire i test di Codeception:
$ php vendor/bin/codecept run
Vediamo subito che qualcosa non va. A prima vista, sembra che il messaggio sia troppo lungo e poco chiaro, ma quando guardiamo più da vicino, tutto diventa ovvio.
Abbiamo eseguito un test, Acceptance , e ha rilevato un errore:
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)
Questo è il colpevole: localhost non è disponibile.
Ed ecco i passaggi dello scenario del nostro test:
1. $I->amOnPage("/")
Ok, apriamo test/acceptance.suite.yml e cambiamo l' url: http://localhost/
in qualcosa che è effettivamente disponibile. Nel mio caso, è il mio host di prova locale, url: https://local.codeception-article.com/
Esegui di nuovo il test e questo è ciò che dovresti ottenere:
Acceptance Tests (1) --------------------------------------------------------------------------------------- Perform actions and result (HelloWorldCept) Ok
Evviva! Il nostro primo test di successo!
Naturalmente, amOnPage()
non è l'unico metodo di test disponibile, lo abbiamo semplicemente individuato per il nostro esempio. Tutti i metodi di test Codeception possono essere suddivisi nei seguenti gruppi:
- Interazione con la pagina:
fillField()
,selectOption()
,submitForm()
,click()
- Affermazioni.
see()
,dontSee()
,seeElement()
,seeInCurrentUrl()
,seeCheckboxIsChecked()
,seeInField()
,seeLink()
. A tutti questi metodi è possibile aggiungere un suffisso e utilizzarlo quando è necessario un metodo che non interrompa lo scenario di test quando non è possibile trovare qualcosa. - Metodi dei cookie:
setCookie()
,grabCookie()
,seeCookie()
- Commento e descrizione degli scenari di test:
amGoingTo()
,wantTo()
) , Expect(expect()
. Usa questi metodi per ottenere test ben commentati e descritti, che ti aiuteranno a ricordare gli obiettivi del test.
Quindi, se dovessimo testare la pagina e-mail di reimpostazione della password, potremmo farlo in questo modo:
<?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');
Sembra che questo dovrebbe farlo, ma cosa succede se ci sono alcune parti caricate da Ajax sulla pagina? Possiamo testare una pagina del genere? La risposta è che Codeception utilizza PhpBrowser, basato su Symfony BrowserKit e Guzzle, per impostazione predefinita. È semplice, veloce e per usarla basta il curl.

Potresti anche usare Selenium e testare le pagine con browser reali. Sì, sarà più lento, ma potrai anche testare JavaScript.
Per prima cosa, devi installare il driver Selenium, cambiare accept.suite.yml e ricostruire la classe AcceptanceTester. Successivamente, puoi utilizzare i metodi wait()
e waitForElement()
. E, cosa più interessante, sarai in grado di risparmiare tempo e risorse usando i metodi saveSessionSnapshot()
e loadSessionSnapshot()
. Questo metodo consente di memorizzare lo stato della sessione e avviare nuovi test nelle sessioni precedenti. Ciò è utile in alcune situazioni, ad esempio nel processo di autorizzazione del test.
Quindi, finiamo con una semplice, ma potente, capacità di testare molte funzioni.
Prove funzionali
OK, è ora di passare ai test funzionali.
$ php vendor/bin/codecept generate:cept functional HelloWorld
Ed ecco cosa otteniamo:
<?php $I = new FunctionalTester($scenario); $I->amOnPage('/'); $I->see('Welcome');
Aspetta cosa?
No, non è un errore. I test funzionali dovrebbero essere scritti allo stesso modo dei test integrativi. La differenza è che i test funzionali interagiscono direttamente con l'applicazione. Ciò significa che non hai bisogno di un server web per eseguire test funzionali e hai più capacità per testare diverse parti della tua applicazione.
Significa che manca il supporto per tutti i framework, ma l'elenco dei framework supportati è ampio: Symfony, Silex, Phalcon, Yii, Zend Framework, Lumen, Laravel. Questo dovrebbe essere sufficiente per la maggior parte dei casi e per la maggior parte degli sviluppatori. Si prega di consultare la documentazione del modulo di Codeception per ottenere un elenco delle funzioni disponibili e quindi attivarlo in functional.suite.yml
.
Prima di procedere allo unit test, permettetemi di fare una piccola digressione. Come avrai notato, abbiamo creato i nostri test con key cept:
$ php vendor/bin/codecept generate: cept acceptance HelloWorld
Questo non è l'unico modo per creare test. Ci sono anche test cesti . La differenza è che puoi strutturare più scenari correlati in una classe:
$ 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'); } }
In questo esempio, i metodi _before()
e _after()
vengono eseguiti prima e dopo ogni test. Un'istanza della classe AcceptanceTester
viene passata a ciascun test, quindi puoi utilizzarla allo stesso modo dei test ces. Questo stile di test può essere utile in determinate situazioni, quindi vale la pena tenerlo a mente.
Test unitario
Tempo per alcuni test unitari.
La codeception si basa su PHPUnit, quindi puoi utilizzare i test scritti per PHPUnit. Per aggiungere nuovi test PHPUnit, utilizzare il seguente approccio:
$ php vendor/bin/codecept generate:phpunit unit HelloWorld
O semplicemente eredita i tuoi test su \PHPUnit_Framework_TestCase
.
Ma se vuoi qualcosa di più, dovresti provare gli unit test di 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()); } }
Niente di insolito per ora. I metodi _before()
e _after()
sono setUp()
e tearDown()
e verranno eseguiti prima e dopo ogni test.
Il vantaggio principale di questo test è nella sua capacità di estendere il processo di test includendo moduli che possono essere attivati in unit.suite.yml
:
- Accesso a memcache e database per tenere traccia delle modifiche (sono supportati MySQL, SQLite, PostgreSQL, MongoDB)
- Test di applicazioni REST/SOAP
- Code
Ogni modulo ha le sue caratteristiche, quindi è meglio controllare la documentazione e raccogliere le informazioni necessarie per ogni modulo prima di procedere ai test veri e propri.
Inoltre, puoi utilizzare il pacchetto Codeception/Specify (che deve essere aggiunto a composer.json
) e scrivere una descrizione in questo modo:
<?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()); }); } }
Il codice PHP all'interno di queste funzioni di chiusura è isolato, quindi le modifiche all'interno non influiranno sul resto del codice. Le descrizioni ti aiuteranno a rendere il test più leggibile e ad identificare più facilmente i test non riusciti.
Come extra opzionale, puoi usare il pacchetto Codeception\Verify
per una sintassi simile a BDD:
<?php public function testUserEmailSave() { verify($map->getEmail())->equals('[email protected]'); }
E ovviamente puoi usare stub:
<?php public function testUserEmailSave() { $user = Stub::make('User', ['getEmail' => '[email protected]']); $this->assertEquals('[email protected]', $user->getEmail()); }
Verdetto: la codeception consente di risparmiare tempo e fatica
Quindi cosa dovresti aspettarti da Codeception? Per chi è? Ci sono avvertimenti?
A mio parere, questo framework di test è adatto a tutti i tipi di team diversi: grandi e piccoli, principianti e professionisti PHP temprati dalla battaglia, coloro che utilizzano un framework popolare e coloro che non utilizzano alcun framework.
In ogni caso, tutto si riduce a questo: Codeception è pronto per la prima serata.
È un framework maturo e ben documentato che può essere facilmente esteso da numerosi moduli. La codeception è moderna, ma basata sulla collaudata PHPUnit, che dovrebbe rassicurare gli sviluppatori che non vogliono sperimentare troppo.
Funziona bene, il che significa che è veloce e non richiede troppo tempo e fatica. Meglio ancora, è relativamente facile da padroneggiare e un'abbondante documentazione dovrebbe aiutare un processo di apprendimento senza problemi.
Codeception è anche facile da installare e configurare, ma vanta molte opzioni avanzate. Sebbene la maggior parte degli utenti non avrà bisogno di tutti (o addirittura, della maggior parte), tutto dipende da cosa intendi farne. Puoi iniziare con le basi e le funzionalità extra torneranno utili prima o poi.