Prendere il controllo dei test

PHP unit testing tutorial - Isolating variables when testing

Per collaudare il codice di un modulo è necessario uno stretto controllo dell'ambiente in cui questo opera. Qualsiasi elemento dovesse variare dietro le quinte, per esempio un file di configurazione, si potrebbe causare il fallimento inaspettato dei test. Si potrebbe trattare di un test non banale e potrebbe essere necessario spendere molte infruttuose ore ad esaminare del codice che in realtà sta funzionando invece che preoccuparsi del problema di confirazione che, di fatto, sta provocando il fallimento. Molto rapidamente i test case diverranno abbastanza complicati da rendere necessario di preoccuparsi delle possibili variazioni.

# time Il tempo è spesso un elemento trascurato nei test

Ci sono solitamente molte ovvie variabili che possono influenzare uno unit test case, specialmente negli ambienti di sviluppo web in cui PHP normalmente opera. Queste comprendono soprattutto il setup del database, i permessi sui file, le risorse di rete e i file di configurazione. La non operatività o i problemi di installazioni di questi componenti provocheranno il fallimento della test suite.

Dobbiamo aggiungere dei test per confermare che questi componenti siano installati? E' una buona idea, ma se si posizionano questi test nel codice di collaudo del modulo si finisce per ingombrare il codice con dettagli che sono irrilevanti per l'obiettivo diretto del test. Dovrebbero essere usare test suite separate.

Un altro problema, tuttavia, è che le macchine di sviluppo devono essere provviste di tutti i moduli di sistena installati, per essere in grado di eseguire le suite di test. I test verranno anche eseguiti più lentamente.

Quando si incontrano questi problemi durante lo sviluppo di solito si creano delle versioni wrapper delle classi che si occupano di gestire tali risorse. I dettagli più problematici delle risorse vengono allora codificate una volta per tutte. Mi piace riferirmi a queste classi come "classi gateway" dal momento che funzionano ai bordi l'applicazione, cioè nell'interfaccia dell'applicazione con il resto del sistema. Le classi gateway sono simulate durante il test da versioni fake. Queste hanno esecuzioni molto più rapide degli originali e vengono spesso chiamate "Server Stub", o, più generalmente, "oggetti Mock". E' un gran risparmio di tempo fare il wrapping e la simulazione di queste risorse.

Una delle risorse esterne a cui si presta solitamente poca attenzione è il tempo.

Per esempio, per collaudare il timeout di una sessione gli sviluppatori solitamente impostano il limite di validità di una sessione a valori molto piccoli, per esempio due secondi, dopo di che utilizzano `sleep(3)` e verificano che la sessione sia scaduta. Tutto questo allunga di tre secondi la test suite e normalmente molto codice per rendere le classi che gestiscono le sessioni abbastanza flessibili. Molto più semplice sarebbe avere un sistema per spostare in avanti l'orologio. Cioè, il controllo sul tempo.

# clock Una classe orologio

Nuovamente, disegneremo il wrapper dell'orologio scrivendo come prima cosa i suoi test. Aggiungeremo un clock test case alla suite tests/all_tests.php: <?php require_once(dirname(__FILE__) . '/simpletest/autorun.php'); require_once(dirname(__FILE__) . '/log_test.php'); require_once(dirname(__FILE__) . '/clock_test.php'); class AllTests extends TestSuite { function __construct() { parent::__construct(); $this->addTest(new TestOfLogging());<strong> $this->addTest(new TestOfClock());</strong> } } ?> Dopo di che si creerà il test case nel nuovo file tests/clock_test.php: <?php require_once(dirname(__FILE__) . '/../classes/clock.php'); <strong> class TestOfClock extends UnitTestCase { function testClockTellsTime() { $clock = new Clock(); $this->assertEqual($clock->now(), time()); } }</strong> ?> Il solo test eseguito al momento è che la nuova classe `Clock` si comporti come un sostituto della funzione PHP `time()`. Scriveremo la funzione di traslazione temporale solo una volta che il test sarà verde. Al momento, ovviamente, siamo rossi:
Fatal error: Failed opening required '../classes/clock.php' (include_path='') in /home/marcus/projects/lastcraft/tutorial_tests/tests/clock_test.php on line 2

Se non vedi questo tipo di errore significa che le tue impostazioni degli errori richiedono aggiustamenti. Può darsi che sia necessario aggiungere queste linee all'inizio del test: ini_set('display_errors', 1); error_reporting(E_ALL); La documentazione di PHP sarà utile, se non ri riuscirà a visualizzare il messaggio di `Fatal error`.

Assumento che l'errore venga visualizzato si proseguirà con la creazione del file classes/clock.php: <strong><?php class Clock { function now() { } } ?></strong> Dopo di che si è pronti per proseguire a scrivere codice.

# AllTests

Fail: TestOfClock -> testClockTellsTime -> [NULL: ] should be equal to [integer: 1050257362]
3/3 test cases complete. 4 passes, 1 fails and 0 exceptions. Questo è facile da risolvere. class Clock { function now() {<strong> return time();</strong> } } E quando otteniamo il verde:

# AllTests

3/3 test cases complete. 5 passes, 0 fails and 0 exceptions. C'è ancora un probelma.

L'orologio continua ad andare avanti durante l'esecuzione del test il che può risultare in secondo di disallineamento. Le possibilità sono remote, ma nel caso si facciano molti collaudi sul tempo si finirà con l'avere una suite di test sbagliata che limiterà severamente la sua utilità. Dobbiamo contrastare rapidamente questo fenomeno e per adesso lo annotiamo nella lista "to do".

Il test di avanzamento appare così: class TestOfClock extends UnitTestCase { function testClockTellsTime() { $clock = new Clock(); $this->assertEqual($clock->now(), time()); } <strong> function testClockAdvance() { $clock = new Clock(); $clock->advance(10); $this->assertEqual($clock->now(), time() + 10); }</strong> } Il codice per ottenere il verde non è distante e comporta solo l'aggiunta di un offset sul tempo. class Clock {<strong> private $offset = 0;</strong> function now() { return time()<strong> + $this->offset</strong>; } <strong> function advance($offset) { $this->offset += $offset; }</strong> }

# tidy Ordinare la test suite

Il nostro file all_tests.php ha delle ridondanze che possiamo evitare. Dobbiamo aggiugere manualmente i test case per ogni singolo file da includere. E' possibile evitarlo, ma l'uso di quanto stiamo per presentare richiede dell'attenzione. La classe `TestSuite` fornisce un comodo metodo chiamato `addFile()` che accetta un file PHP come parametro. Il meccanismo prende nota di tutte le classi presenti nel file, le include e analizza ogni nuova classe creata. Se queste sono derivate da `SimpleTestCase` le aggiunge come nuove `TestSuite`.

Ecco una versione modificata della test suite in cui si utilizza questo metodo: <?php<strong> require_once(dirname(__FILE__) . '/simpletest/autorun.php');</strong> class AllTests extends TestSuite { function AllTests() { parent::__construct();<strong> $this->addFile('log_test.php'); $this->addFile('clock_test.php');</strong> } } ?> I punti critici sono:

1. Se il file fosse già stato incluso, non verrà aggiunta alcuna classe al gruppo.
2. Se il file contiene altre classi che discendono da `SimpleTestCase`, anche queste verranno aggiunte al gruppo.

Nella pratica, nessuno di questi punti rappresenta un problema. Le suite di test normalmente hanno una struttura ad albelo per cui è raro che un test sia presente in due posizioni.

A proposito dell'inclusione di classi extra, queste sono comunque derivate da `SimpleTestCase`. Si tratta di classi utilizzate come superclassi di aiuto per altri test. E' sufficiente indicarle come `abstract` per impedire che vengano eseguite.

Dovremo veramente correggere l'inconveniente del possibile slittamento dell'orologio e sarà quindi il prossimo passo.

Il tempo è spesso un elemento trascurato nei test. Una classe orologio che permette di controllare il tempo Ordinare la test suite.
The previous section is grouping into test suites. The next section is subclassing test cases. You will need the SimpleTest unit tester for the examples.
software development, php programming, programming php, software development tools, php tutorial, free php scripts, software architecture, php testing, unit test, php testing, development process