In questo articolo porto un esempio di test con Laravel.
Laravel consente di eseguire due tipi di test: Unit per piccoli test su singole funzioni del controller o del model. Feature per testare intere funzionalità dell’applicativo dalla richesta HTTP alla produzione dell’output.
Laravel crea i test in due directory:
<APP>/tests/Feature <APP>/test/Unit
Per creare un test (di defult si va sulle Features):
$ php artisan make:test UserTest [--unit]
Aggiungiamo --unit
solo se vogliamo fare un test di unità (per un singolo metodo per esempio). Il nome del test possiamo sceglierlo come vogliamo, basta che ci ricordi cosa fa. Il nome finisce sempre per “Test”.
Faccio girare i test
$ php artisan test PASS Tests\Unit\ExampleTest ✓ example PASS Tests\Feature\ComplexTest ✓ example PASS Tests\Feature\ExampleTest ✓ example Tests: 3 passed Time: 0.16s
Infatti quando creo i test la prima volta, lui aggiunge già un file tests/Feature/ExampleTest.php
, io ne ho aggiunto un secondo che fa un test standard di risposta all’URL http://myapp.local/ (ho configurato il virtualhost Apache).
In questo esempio costruirò una classe per la gestione del tipo “numero complesso”, la classe Complex.
In una prima versione definisco il costruttore che crea l’oggetto Complex a partire dalla parte reale e immaginaria e poi scrivo qualche setter e qualche getter per consentire accesso e modifica alle variabili private $real
e $imag
:
<?php namespace App; use PHPUnit\Util\Exception; class Complex { private float $real; private float $imag; private float $modulus; private float $phase; public function __construct($x, $y) { $this->setReal($x); $this->setImag($y); $this->setModulus(); $this->setPhase(); } public function getReal(): float { return $this->real; } public function getImag(): float { return $this->imag; } public function getModulus(): float { return $this->modulus; } public function getPhase(): float { return $this->phase; } public function setReal($x) { $this->real = ($x == null) ? 0 : $x; } public function setImag($y) { $this->imag = ($y == null) ? 0 : $y; }
E scrivo alcuni test per mettere alla prova questi medodi: lo faccio nel file <APP>/test/Feature/ComplexTest.php
;
class ComplexTest extends TestCase { /** * A basic feature test example. * * @return void */ public function test_example() { $response = $this->get('/'); $response->assertStatus(200); } public function test_setReal() { $r = 1; $z = new Complex(null, null); $z->setReal($r); $x = $z->getReal(); $this->assertTrue($x == $r); } public function test_setImag() { $i = 1; $z = new Complex(null, null); $z->setImag($i); $y = $z->getImag(); $this->assertTrue($y == $i); }
Lo spirito è il seguente: provo il metodo e confronto il risultato con quello che mi aspetto che faccia. Se non lo fa c’è un problema da risolvere. Per fare questo c’è il metodo assertTrue()
che testa che una condizione sia vera. Ad esempio nel metodotest_setReal()
viene creato un numero complesso nullo (con parte reale e immaginaria nulle) e poi viene impostata la parte reale a 1 con setReal()
. Successivamente la leggo con getReal()
; mi aspetto che il risultato sia 1. Per questo utilizzo il metodo assertTrue($x == $r)
.
Scrivo poi i metodi che impostano il modulo e la fase (già dentro al costruttore così le ho a disposizione fin dall’inizio) e con un metodo print() stampo il numero nella rappresenzazione cartesiana z = x + i y.
Per eseguire il test, lancio da riga di comando:
$ php artisan test PASS Tests\Unit\ExampleTest ✓ example PASS Tests\Feature\ComplexTest ✓ example ✓ set real ✓ set imag ✓ set modulus ✓ set phase ✓ print ✓ real print ✓ imag print ✓ modulus ✓ phase PASS Tests\Feature\ExampleTest ✓ example Tests: 12 passed Time: 0.14s $
Se invece qualcosa va storto si vede un output del genere:
$ php artisan test PASS Tests\Unit\ExampleTest ✓ example FAIL Tests\Feature\ComplexTest ✓ example ⨯ set real ⨯ set imag ✓ set modulus ✓ set phase ✓ print ✓ real print ✓ imag print ✓ modulus ✓ phase PASS Tests\Feature\ExampleTest ✓ example --- • Tests\Feature\ComplexTest > set real PHPUnit\Util\Exception Phase undefined at app/Complex.php:68 64▕ $res = M_PI_2; 65▕ } else if ($this->imag < 0) { 66▕ $res = - M_PI_2; 67▕ } else { ➜ 68▕ throw new Exception('Phase undefined'); 69▕ } 70▕ } 71▕ 72▕ return $this->phase = $res; 1 app/Complex.php:19 App\Complex::setPhase() 2 tests/Feature/ComplexTest.php:27 App\Complex::__construct()
e abbiamo tutti i dettagli per capire dove dobbiamo correggere.
Sommario
Automazione dei test
Un aspetto ancora più bello di Laravel è che possiamo automatizzare i test quando vogliamo, ad esempio prima di un commit su Git.
Ma lo faccio in un altro articolo.
Commenti recenti