Scrivere Unit Test con PHPUnit, Parte 3: Configurazione XML
Nei post precedenti di questa serie, ho trattato i seguenti due argomenti:
- Scrivere Unit Test con PHPUnit, Parte 1: Il Set-Up. Una guida per iniziare a scrivere test PHPUnit attraverso l’uso di una cache di base e utilizzando il metodo setUp del framework.
- Scrivere unit test con PHPUnit, parte 2: The Tear Down. Un tutorial su come scrivere unit test che sfruttano correttamente i metodi setUp e tearDown di PHPUnit.
Ciascuno dei precedenti ha lo scopo di fornire un primer su come iniziare a scrivere test unitari di base. Le cose possono diventare più complesse soprattutto con la crescita di un’applicazione o di un progetto (ma è sempre vero, giusto?).
Ma per essere sicuri che uno sia preparato per questo, c’è un componente finale per lo unit test su cui credo dovremmo concentrarci ed è la comprensione del file di configurazione XML PHPUnit (che potresti aver visto in altri progetti come phpunit.xml).
Configurazione XML dell’unità PHP
Quindi, in questo post, configurerò un semplice progetto che utilizza PHPUnit, scrive alcuni test come quelli che abbiamo già visto e sfrutta un file di configurazione per automatizzare i test.
Inoltre, farò il possibile per spiegare al meglio le parti necessarie del file di configurazione in modo che tu possa includerne uno nel tuo prossimo progetto.
1 Eliminare i file
Prima di iniziare a scrivere effettivamente codice verificabile, è importante conoscere i file che saranno necessari per far funzionare il processo.
Quanto segue è, più o meno, come organizziamo le cose dall’inizio di un progetto:
- una directory per i test,
- il file phpunit.xml
Alla fine vedrai anche:
- i file che compongono il progetto,
- i test che verificano detti file.
A questo punto, però, diamo un’occhiata al file di configurazione XML e poi tentiamo di eseguire PHPUnit automaticamente senza altri parametri.
2 Nozioni di base per il file di configurazione
Per prima cosa, diamo un’occhiata al file di configurazione di base:
<?xml version="1.0" encoding="UTF-8"?>
<!-- http://phpunit.de/manual/4.1/en/appendixes.configuration.html -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd"
bootstrap="./tests/bootstrap.php"
backupGlobals="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
>
<testsuites>
<testsuite name="AcmeTests">
<directory>./tests</directory>
</testsuite>
</testsuites>
<logging>
<log type="coverage-text" target="php://stdout" showUncoveredFiles="true"></log>
</logging>
</phpunit>
Ora capiamo cosa esattamente stiamo guardando (diverso dal semplice XML).
- phpunit. Il nodo padre svolge il solito lavoro di definizione dello schema per il file XML, ma ci sono alcuni altri componenti di cui ci occupiamo in particolare:
- backupGlobals. Questo è in realtà correlato a un’annotazione che possiamo fare nel nostro codice sorgente. I globali sono qualcosa che dovremmo cercare di evitare nella programmazione orientata agli oggetti, ma se scegli di usarne uno o devi usarne uno, questo dirà a PHPUnit di gestire i valori che le variabili globali stanno mantenendo (e ti darà la possibilità di ripristinare loro). In genere lo lascio così com’è.
- bootstrap. Questo è facoltativo, ma se scegli di includere altri file con i tuoi test (come l’inserimento di una libreria beffarda, parte di WordPress o una libreria di terze parti), allora questo sarà tutto per te per definire la posizione dello script che deve eseguire. Deridere e introdurre WordPress non rientra nell’ambito di questo post, ma è qualcosa che probabilmente esamineremo in futuro poiché è utile durante il test dei plug-in. Per ora, includerò un semplice caricatore automatico che fondamentalmente aggiunge tutti i file nella radice della directory del progetto. La fonte completa sarà condivisa più avanti in questo post.
- colori. Se desideri che la console stampi un rapporto dei tuoi test e lo faccia utilizzando i colori (per aiutare a identificare più facilmente avvisi, avvisi, errori e così via), impostalo su true.
- I seguenti sono tutti valori booleani. Raccomando di impostarli su true per i rapporti più aggressivi possibili. In questo modo, non te la caverai semplicemente vedendo scivolare avvisi o avvisi mentre ti preoccupi solo degli errori. Questo è più un esercizio sulla qualità del codice che altro.
- convertErrorsToExceptions
- convertNoticesToExceptions
- convertWarningsToExceptions
- le testsuite sono costituite da raccolte di test. Poiché un determinato progetto può avere più test, è importante assicurarsi di assegnare a ciascuna suite un nome univoco e fare riferimento al percorso corretto del gruppo di test. Per il nostro esempio, avremo solo una singola suite di test e si trova nella directory test.
- la registrazione è una funzionalità che può essere semplice come stampare i dati nella console o utilizzare una libreria di terze parti (come Clover) per generare report che aiutano con l’integrazione continua. Dal momento che devo ancora discutere di quest’ultimo in nessuno dei miei post precedenti, continueremo con la console come metodo principale di output. Pertanto, abbiamo php ://stdout come unico output di registrazione.
Detto questo, il nostro file XML ha tutto ciò di cui PHPUnit ha bisogno per funzionare senza altri parametri.
Ricorda, tuttavia, prima di procedere con il resto di questo articolo, presumo che tu abbia installato PHPUnit a livello globale sul tuo sistema utilizzando Composer. In caso contrario, rivedi questo articolo in quanto ti fornirà le istruzioni su come farlo.
Una volta fatto, puoi verificare che PHPUnit sia installato inserendo il seguente comando nel tuo terminale:
$ which phpunit
E dovresti vedere qualcosa come il seguente:
Se vedi qualcosa di simile a quanto sopra, puoi eseguire PHPUnit ovunque dal tuo sistema.
3 Il file Bootstrap
Prima di andare oltre, scriviamo un file bootstrap di base. Lo chiameremo bootstrap.php e lo rilasceremo nella nostra directory test. Includerà quanto segue:
<?php
// This array has a single file but could whole the contents of an entire directory.
$files = [
dirname(__DIR__).'/AcmeCache.php',
];
foreach ($files as $file) {
if (file_exists($file)) {
require_once $file;
}
}
Questo è un semplice "caricatore automatico" (che io lo chiamo con esitazione dato che sta solo scorrendo i file e richiedendoli, ma funziona per i nostri scopi).
A questo punto, impostiamo un test di base.
4 Un test di base fallito
Se leggi qualcosa sullo sviluppo basato su test, probabilmente sentirai parlare di un ciclo rosso-verde-ripetitivo. C’è molto da dire a riguardo e consiglio di leggerlo, ma non è lo scopo di questo post.
Invece, siamo più concentrati sulla scrittura di test che corrispondono a ciò che dobbiamo fare, giusto? Quindi, detto questo, facciamo quanto segue:
- crea una directory da cui avrai alcuni file PHP di base che testeremo,
- nella radice della directory, crea anche phpunit.xml e popolalo usando il codice condiviso in precedenza in questo post
- creare una directory test in cui collocheremo i nostri test.
Ora, dal Terminale, cambia la directory nella directory del progetto (che è certamente mancante, per ora) e quindi esegui semplicemente php unit:
$ phpunit
Supponendo che tutto sia impostato correttamente, dovresti vedere qualcosa del genere:
Dal momento che non abbiamo codice e test, vedremo naturalmente l’output sopra, giusto? Quindi scriviamo un singolo test che verrà eseguito (e fallito) poiché non c’è codice da testare effettivamente.
Innanzitutto, nella directory test crea un file chiamato AcmeCacheTest.php. E facciamogli fare qualcosa di semplice come istanziare un oggetto cache che alla fine creeremo.
<?php
namespace AcmeTests;
use PHPUnitFrameworkTestCase;
use AcmeAcmeCache;
class AcmeCacheTest extends TestCase
{
private $cache;
public function setUp()
{
$this->cache = new AcmeCache();
}
public function testCacheExists()
{
$this->assertNotNull($this->cache);
}
}
Prima di eseguire il test, notare che:
- Assicurati di utilizzare PHPUnitFrameworkTestCase
- E chiedi alla nostra classe di estendere TestCase
Questo fa parte di ciò che rende l’utilizzo di PHPUnit così semplice. Una volta fatto, esegui il codice seguente dalla radice del tuo progetto:
$ phpunit
Dopodiché, dovresti vedere quanto segue:
Nota che questo produrrà un test fallito e ti dirà dove è stato trovato il problema, il file e la riga.
Per risolvere questo problema, dobbiamo scrivere una classe:
<?php
namespace Acme;
class AcmeCache
{
private $duration;
public function __construct()
{
$this->duration = 43200;
}
public function setDuration(int $duration)
{
$this->duration = $duration;
}
public function getDuration(): int
{
return $this->duration;
}
}
4 Alcuni test di base e di superamento
Il test di superamento di base (che sarà basato sul codice precedente) includerà quanto segue:
- un file con spazio dei nomi,
- rappresenterà una semplice cache,
- verrà caricato automaticamente da PHPUnit utilizzando il file bootstrap.php condiviso sopra
- e avrà una durata impostata nel suo costruttore insieme a un setter e un getter per il valore
Per prima cosa, verifichiamo che siamo in grado di impostare la classe e che non sia nulla. Questa è un’affermazione un po ‘non necessaria poiché sappiamo che avremo una classe correttamente istanziata, ma ci fa entrare nel solco della scrittura di test:
<?php
namespace AcmeTests;
use PHPUnitFrameworkTestCase;
use AcmeAcmeCache;
class AcmeCacheTest extends TestCase
{
private $cache;
public function setUp()
{
$this->cache = new AcmeCache();
}
public function testCacheExists()
{
$this->assertNotNull($this->cache);
}
}
Ed esegui il test:
Quindi, verifichiamo che il valore predefinito della cache sia impostato:
<?php
namespace AcmeTests;
use PHPUnitFrameworkTestCase;
use AcmeAcmeCache;
class AcmeCacheTest extends TestCase
{
private $cache;
public function setUp()
{
$this->cache = new AcmeCache();
}
public function testCacheExists()
{
$this->assertNotNull($this->cache);
}
public function testDefaultCacheValue()
{
$this->assertSame(43200, $this->cache->getDuration());
}
}
Come per il passaggio precedente, esegui i test e ora dovresti vedere due test superati:
Infine, proviamo per vedere se siamo in grado di modificare correttamente il valore:
<?php
namespace AcmeTests;
use PHPUnitFrameworkTestCase;
use AcmeAcmeCache;
class AcmeCacheTest extends TestCase
{
private $cache;
public function setUp()
{
$this->cache = new AcmeCache();
}
public function testCacheExists()
{
$this->assertNotNull($this->cache);
}
public function testDefaultCacheValue()
{
$this->assertSame(43200, $this->cache->getDuration());
}
public function testSetCustomDuration()
{
$duration = 4200;
$this->cache->setDuration($duration);
$this->assertSame($duration, $this->cache->getDuration());
}
}
E le ultime tre prove superate:
E il gioco è fatto:
- un file XML PHPUnit,
- un semplice bootstrap,
- una singola classe con namespace,
- unit test per ogni metodo della classe
Certo, è semplice, ma questo pone le basi per molto di più di quello che molte persone già fanno con i loro test.
Inoltre, ti dà qualcosa su cui costruire man mano che le tue capacità di prova diventano più forti.
C’è di più? (Sempre giusto?)
Infine, se sei ansioso di immergerti davvero nel file di configurazione, puoi leggere la spiegazione approfondita del manuale al riguardo.
Nota, tuttavia, tutto ciò che è descritto sopra mira ad essere ciò di cui hai bisogno per iniziare a configurare il tuo file di configurazione XML PHPUnit.




