TestCase

In einfachen Tests können die Assertions einfach hintereinander stehen. Manchmal ist es aber vorteilhaft, die Assertions in eine Testklasse zu verpacken und sie so zu strukturieren.

Die Klasse muss Tester\TestCase erweitern, und wir nennen sie kurz TestCase. Die Klasse muss Testmethoden enthalten, deren Namen mit test beginnen. Diese Methoden werden als Tests ausgeführt:

use Tester\Assert;

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

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

# Testmethoden ausführen
(new RectangleTest)->run();

Ein so geschriebener TestCase lässt sich noch mit den Methoden setUp() und tearDown() erweitern. Sie werden vor bzw. nach jeder Testmethode aufgerufen:

use Tester\Assert;

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

	protected function tearDown()
	{
		# Aufräumen
	}

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

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

# Testmethoden ausführen
(new NextTest)->run();

/*


Reihenfolge der Methodenaufrufe
-------------------------------
setUp()
testOne()
tearDown()

setUp()
testTwo()
tearDown()
*/

Tritt in der Phase setUp() oder tearDown() ein Fehler auf, schlägt der Test insgesamt fehl. Tritt ein Fehler in der Testmethode selbst auf, wird die Methode tearDown() trotzdem ausgeführt, Fehler in ihr werden dabei jedoch unterdrückt.

Innerhalb einer Testmethode können Sie den aktuellen Test jederzeit mit $this->skip('Grund') überspringen, zum Beispiel wenn eine Voraussetzung nicht erfüllt ist.

Wir empfehlen, am Anfang der Testdatei die Annotation @testCase zu schreiben. Der Test-Runner auf der Kommandozeile führt die einzelnen Methoden des TestCase dann in eigenen Prozessen und parallel in mehreren Threads aus. Das kann den gesamten Testvorgang deutlich beschleunigen.

<?php
/** @testCase */

Annotationen von Methoden

Für Testmethoden stehen mehrere Annotationen zur Verfügung, die das Testen erleichtern. Schreiben Sie sie über die Testmethode.

@throws

Sie entspricht der Verwendung von Assert::exception() innerhalb der Testmethode, die Schreibweise ist aber übersichtlicher:

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


/**
 * @throws LogicException  Wrong argument order
 */
public function testTwo()
{
	// ...
}

@dataProvider

Diese Annotation ist nützlich, wenn Sie die Testmethode mehrfach mit verschiedenen Parametern ausführen wollen. (Verwechseln Sie sie nicht mit der gleichnamigen Annotation für Testdateien.)

Geben Sie danach den Namen einer Methode an, die die Argumente für die Testmethode liefert. Diese Methode muss ein Array oder ein Traversable-Objekt zurückgeben. Ein einfaches Beispiel:

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


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

Die zweite Variante der Annotation @dataProvider nimmt als Parameter den Pfad zu einer INI-Datei entgegen (relativ zur Testdatei). Die Methode wird so oft aufgerufen, wie die INI-Datei Sektionen hat. Datei loop-args.ini:

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

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

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

und die Methode, die die INI-Datei verwendet:

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

Ebenso können Sie statt einer INI-Datei auf ein PHP-Skript verweisen. Es muss ein Array oder ein Traversable-Objekt zurückgeben. Datei loop-args.php:

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

Wie beim Data Provider für Testdateien können Sie hinter den Dateinamen eine Filterabfrage anhängen, um die Methode nur für die passenden Sektionen auszuführen.