TestCase

V jednoduchých testech mohou aserce následovat jedna za druhou. Někdy je ale výhodnější aserce zabalit do testovací třídy a tak je strukturovat.

Třída musí být potomkem Tester\TestCase a zjednodušeně o ní mluvíme jako o testcase. Třída musí obsahovat testovací metody začínající na test. Tyto metody budou spuštěny jako testy:

use Tester\Assert;

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

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

# Spuštění testovacích metod
(new RectangleTest)->run();

Takto napsaný test lze dále obohatit o metody setUp() a tearDown(). Jsou volány před, resp. za každou testovací metodou:

use Tester\Assert;

class NextTest extends Tester\TestCase
{
	protected function setUp()
	{
		# Příprava
	}

	protected function tearDown()
	{
		# Úklid
	}

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

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

# Spuštění testovacích metod
(new NextTest)->run();

/*


Pořadí volání metod
-------------------
setUp()
testOne()
tearDown()

setUp()
testTwo()
tearDown()
*/

Pokud dojde k chybě ve fázi setUp() nebo tearDown(), test celkově selže. Pokud dojde k chybě v testovací metodě, metoda tearDown() se přesto spustí, avšak s potlačením chyb v ní.

Uvnitř testovací metody můžete kdykoli aktuální test přeskočit voláním $this->skip('důvod'), například když není splněný nějaký předpoklad.

Doporučujeme na začátek testu napsat anotaci @testCase, potom bude spouštěč testů z příkazové řádky pouštět jednotlivé metody testcase v samostatných procesech a paralelně ve více vláknech. To může výrazně urychlit celý proces testování.

<?php
/** @testCase */

Anotace metod

U testovacích metod máme k dispozici několik anotací, které nám testování usnadní. Zapisujeme je k testovací metodě.

Od verze 2.7 je můžeme zapsat také jako PHP atributy ze jmenného prostoru Tester\Attributes. Fungují úplně stejně jako anotace, ale IDE vám je doplní a zkontroluje názvy tříd, které v nich uvedete. Pokud má metoda obojí, platí atribut. V příkladech níže je vždy nejprve atribut a pak totéž jako anotace.

@throws

Je ekvivalentem použití Assert::exception() uvnitř testovací metody. Zápis je ale přehlednější:

use Tester\Attributes\Throws;

#[Throws(RuntimeException::class)]
public function testOne()
{
	// ...
}


#[Throws(LogicException::class, 'Wrong argument order')]
public function testTwo()
{
	// ...
}

Nepovinný druhý argument je vzor, kterému musí odpovídat zpráva výjimky, stejně jako u Assert::exception(). Místo třídy výjimky přijímá atribut i konstantu E_*, takže test může očekávat také PHP chybu, například varování: #[Throws(E_WARNING)].

Totéž zapsané anotacemi:

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


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

@dataProvider

Chceme-li testovací metodu spustit vícekrát, ale s jinými parametry, hodí se právě tato anotace. (Nezaměňujte ji se stejnojmennou anotací pro soubory.)

Za ní uvedeme název metody, která vrací argumenty pro testovací metodu. Metoda musí vrátit pole nebo Traversable. Jednoduchý příklad:

use Tester\Attributes\DataProvider;

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


#[DataProvider('getLoopArgs')]
public function testLoop($a, $b, $c)
{
	// ...
}

Totéž zapsané anotací:

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

Pokud data provider nevrátí vůbec žádnou sadu dat, test selže. Prázdný provider je téměř vždy chyba, třeba prázdný soubor nebo filtr, kterému nic nevyhovuje, a testovací metoda, která se potichu vůbec nespustila, by vypadala, jako by prošla.

Druhá varianta anotace @dataProvider přijímá jako parametr cestu k INI souboru (relativně k souboru s testem). Metoda je volána tolikrát, kolik je v INI souboru sekcí. Soubor loop-args.ini:

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

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

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

a metoda, která INI soubor využívá:

#[DataProvider('loop-args.ini')]
public function testLoop($a, $b, $c)
{
	// ...
}

Jako anotaci zapíšeme @dataProvider loop-args.ini.

Obdobně můžeme namísto INI souboru odkázat na PHP skript. Ten musí vrátit pole nebo Traversable. Soubor loop-args.php:

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

Stejně jako u data provideru pro soubory lze za název souboru připojit filtrovací dotaz a spustit metodu jen pro vyhovující sekce. U atributu dotaz předáme jako druhý argument, například #[DataProvider('loop-args.ini', 'one')].

Metoda může mít i více data providerů, zapsaných jako více atributů nebo anotací. Spustí se pak postupně se sadami dat ze všech.