Test Laravel

Laravel Test
Laravel test

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.

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.

Riferimenti

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.

Questo sito utilizza Akismet per ridurre lo spam. Scopri come vengono elaborati i dati derivati dai commenti.