TestCase

In einfachen Tests können Assertions aufeinander folgen. Manchmal ist es jedoch vorteilhafter, Assertions in einer Testklasse zu verpacken und sie so zu strukturieren.

Die Klasse muss von Tester\TestCase erben und wird vereinfacht als testcase bezeichnet. Die Klasse muss Testmethoden enthalten, die 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(/* ... */);
	}
}

# Ausführung der Testmethoden
(new RectangleTest)->run();

Ein so geschriebener Test kann weiter um Methoden setUp() und tearDown() erweitert werden. Sie werden vor bzw. nach jeder Testmethode aufgerufen:

use Tester\Assert;

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

	public function tearDown()
	{
		# Aufräumen
	}

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

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

# Ausführung der Testmethoden
(new NextTest)->run();

/*


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

setUp()
testTwo()
tearDown()
*/

Wenn in der setUp()- oder tearDown()-Phase ein Fehler auftritt, schlägt der Test insgesamt fehl. Wenn in der Testmethode ein Fehler auftritt, wird die Methode tearDown() dennoch ausgeführt, jedoch mit unterdrückten Fehlern darin.

Wir empfehlen, am Anfang des Tests die Annotation @testCase zu schreiben. Dann führt der Kommandozeilen-Teststarter die einzelnen Methoden des Testcases in separaten Prozessen und parallel in mehreren Threads aus. Dies kann den gesamten Testprozess erheblich beschleunigen.

<?php
/** @testCase */

Annotationen von Methoden

Für Testmethoden stehen uns mehrere Annotationen zur Verfügung, die uns das Testen erleichtern. Wir schreiben sie zur Testmethode.

@throws

Ist äquivalent zur Verwendung von Assert::exception() innerhalb der Testmethode. Die Schreibweise ist jedoch übersichtlicher:

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


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

@dataProvider

Wenn wir eine Testmethode mehrfach, aber mit unterschiedlichen Parametern ausführen möchten, ist diese Annotation nützlich. (Nicht zu verwechseln mit der gleichnamigen Annotation für Dateien.)

Dahinter geben wir den Namen der Methode an, die die Argumente für die Testmethode zurückgibt. Die Methode muss ein Array oder Traversable 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 akzeptiert als Parameter den Pfad zu einer INI-Datei (relativ zur Testdatei). Die Methode wird so oft aufgerufen, wie es Abschnitte in der INI-Datei gibt. 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)
{
	// ...
}

Ähnlich können wir anstelle einer INI-Datei auf ein PHP-Skript verweisen. Dieses muss ein Array oder Traversable 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],
];