TestCase

Dans les tests simples, les assertions peuvent se succéder les unes après les autres. Il est cependant parfois avantageux d'envelopper les assertions dans une classe de test pour les structurer.

La classe doit étendre Tester\TestCase et nous l'appelons simplement un TestCase. Elle doit contenir des méthodes de test commençant par test. Ces méthodes seront exécutées comme des tests :

use Tester\Assert;

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

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

# Exécution des méthodes de test
(new RectangleTest)->run();

Un TestCase écrit de cette façon peut encore être enrichi des méthodes setUp() et tearDown(). Elles sont appelées respectivement avant et après chaque méthode de test :

use Tester\Assert;

class NextTest extends Tester\TestCase
{
	protected function setUp()
	{
		# Préparation
	}

	protected function tearDown()
	{
		# Nettoyage
	}

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

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

# Exécution des méthodes de test
(new NextTest)->run();

/*


Ordre d'appel des méthodes
--------------------------
setUp()
testOne()
tearDown()

setUp()
testTwo()
tearDown()
*/

Si une erreur survient pendant la phase setUp() ou tearDown(), le test échoue globalement. Si une erreur survient dans la méthode de test elle-même, la méthode tearDown() est tout de même exécutée, mais les erreurs qui s'y produisent sont supprimées.

Au sein d'une méthode de test, vous pouvez à tout moment ignorer le test courant en appelant $this->skip('raison'), par exemple lorsqu'un prérequis n'est pas rempli.

Nous recommandons d'écrire l'annotation @testCase au début du fichier de test. Le lanceur de tests en ligne de commande exécutera alors les différentes méthodes du TestCase dans des processus distincts et en parallèle, sur plusieurs threads. Cela peut accélérer nettement l'ensemble du processus de test.

<?php
/** @testCase */

Annotations de méthodes

Plusieurs annotations sont disponibles pour les méthodes de test afin de faciliter les tests. Écrivez-les au-dessus de la méthode de test.

@throws

Elle équivaut à l'utilisation d'Assert::exception() à l'intérieur de la méthode de test, mais l'écriture est plus claire :

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


/**
 * @throws LogicException  Mauvais ordre des arguments
 */
public function testTwo()
{
	// ...
}

@dataProvider

Cette annotation est utile lorsque vous voulez exécuter la méthode de test plusieurs fois avec des paramètres différents. (Ne la confondez pas avec l'annotation du même nom pour les fichiers de test.)

Indiquez après elle le nom d'une méthode qui renvoie les arguments de la méthode de test. Cette méthode doit renvoyer un tableau ou un objet Traversable. Exemple simple :

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


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

La seconde variante de l'annotation @dataProvider accepte en paramètre un chemin vers un fichier INI (relatif au fichier de test). La méthode est appelée autant de fois qu'il y a de sections dans le fichier INI. Fichier loop-args.ini :

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

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

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

et la méthode qui utilise ce fichier INI :

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

De la même façon, au lieu d'un fichier INI, vous pouvez référencer un script PHP. Il doit renvoyer un tableau ou un objet Traversable. Fichier loop-args.php :

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

Comme pour le data provider des fichiers de test, vous pouvez ajouter après le nom du fichier une requête de filtrage afin de n'exécuter la méthode que pour les sections correspondantes.