TestCase

Nei test semplici le asserzioni possono susseguirsi una dopo l'altra. A volte però conviene racchiudere le asserzioni in una classe di test per dare loro una struttura.

La classe deve estendere Tester\TestCase e la chiamiamo semplicemente TestCase. La classe deve contenere metodi di test che iniziano con test. Questi metodi verranno eseguiti come test:

use Tester\Assert;

class RectangleTest extends Tester\TestCase
{
	public function testOne()
	{
		Assert::same(/* ... */);
	}

	public function testTwo()
	{
		Assert::match(/* ... */);
	}
}

# esecuzione dei metodi di test
(new RectangleTest)->run();

Un TestCase scritto così si può arricchire ulteriormente con i metodi setUp() e tearDown(). Vengono chiamati rispettivamente prima e dopo ogni metodo di test:

use Tester\Assert;

class NextTest extends Tester\TestCase
{
	protected function setUp()
	{
		# preparazione
	}

	protected function tearDown()
	{
		# pulizia
	}

	public function testOne()
	{
		Assert::same(/* ... */);
	}

	public function testTwo()
	{
		Assert::match(/* ... */);
	}
}

# esecuzione dei metodi di test
(new NextTest)->run();

/*


Ordine delle chiamate dei metodi
--------------------------------
setUp()
testOne()
tearDown()

setUp()
testTwo()
tearDown()
*/

Se si verifica un errore nella fase setUp() o tearDown(), il test fallisce nel suo insieme. Se l'errore si verifica nel metodo di test stesso, il metodo tearDown() viene comunque eseguito, ma gli eventuali errori al suo interno vengono soppressi.

Dentro un metodo di test potete saltare in qualsiasi momento il test corrente chiamando $this->skip('motivo'), per esempio quando una condizione preliminare non è soddisfatta.

Consigliamo di scrivere all'inizio del file del test l'annotazione @testCase. Il runner da riga di comando eseguirà allora i singoli metodi del TestCase in processi separati e in parallelo su più thread. Questo può accelerare notevolmente l'intero processo di test.

<?php
/** @testCase */

Annotazioni dei metodi

Per i metodi di test sono disponibili alcune annotazioni che facilitano il lavoro. Scrivetele sopra il metodo di test.

@throws

Equivale all'uso di Assert::exception() dentro il metodo di test, ma la notazione è più chiara:

/**
 * @throws RuntimeException
 */
public function testOne()
{
	// ...
}


/**
 * @throws LogicException  Ordine degli argomenti sbagliato
 */
public function testTwo()
{
	// ...
}

@dataProvider

Questa annotazione torna utile quando volete eseguire il metodo di test più volte con parametri diversi. (Non confondetela con l'annotazione omonima per i file di test.)

Dopo di essa indicate il nome di un metodo che restituisce gli argomenti per il metodo di test. Questo metodo deve restituire un array o un oggetto Traversable. Un esempio semplice:

public function getLoopArgs()
{
	return [
		[1, 2, 3],
		[4, 5, 6],
		[7, 8, 9],
	];
}


/**
 * @dataProvider getLoopArgs
 */
public function testLoop($a, $b, $c)
{
	// ...
}

La seconda variante dell'annotazione @dataProvider accetta come parametro il percorso di un file INI (relativo al file del test). Il metodo viene chiamato tante volte quante sono le sezioni nel file INI. File loop-args.ini:

[one]
a=1
b=2
c=3

[two]
a=4
b=5
c=6

[three]
a=7
b=8
c=9

e il metodo che usa il file INI:

/**
 * @dataProvider loop-args.ini
 */
public function testLoop($a, $b, $c)
{
	// ...
}

Allo stesso modo, invece di un file INI potete indicare uno script PHP. Deve restituire un array o un oggetto Traversable. File loop-args.php:

return [
	['a' => 1, 'b' => 2, 'c' => 3],
	['a' => 4, 'b' => 5, 'c' => 6],
	['a' => 7, 'b' => 8, 'c' => 9],
];

Come per il data provider dei file di test, dopo il nome del file potete aggiungere una query di filtro per eseguire il metodo solo per le sezioni corrispondenti.