PHPUnit - jednotkové testování v PHP
Osnova
- Jednotkové testy
- PHPUnit
Jednotkové testy
Problém: změnou kódu programové jednotky mohou vzniknout chyby
Řešení: jednotkové (unit) testy
- verifikace
- automatické (programové) testování jednotek
- regresní testování
- nejblíže vývojáři
Jednotka
Jednotka je nejmenší testovatelná část software (procedura, objekt …)
Terminologie (a)
Unit testy se neliší mezi různými technologiemi a jazyky
- JUnit, PHPUnit, SimpleTest …
- Test fixtures (kontext)
- sada předpokladů nebo stavy, které jsou potřeba, aby test mohl uspět
- Test case (testovaný případ)
- sada podmínek – testovaná jednotka pracuje správně či nikoliv
- Test suites (sada testů)
- sada testů, které sdílejí tentýž kontext, na pořadí nezáleží
- Assertion (tvrzení, jednotková logická funkce)
- funkce, metoda, makro atp., ověřuje chování testované jednotky, chyba znamená ukončení prováděného testu a indikaci chyby.
Terminologie (b)
- method_stub
- simuluje chování funkce
- mock object
- simuluje reálný objekt, kontrolovaný programátorem
- tyto objekty netestujeme, ale ony mohou testovat naše objekty
- fake object
- jednodušší mock objekt - pouze implementuje stejný interface jako reálný objekt
Struktura testu
// příprava prostředí pro testy
setup();
// tělo testu
testXY();
testXZ();
...
// úklid na konci (nehledě na kladný/záporný výsledek testu)
teardown();
PHPUnit - dokumentace, instalace
- Homepage
- Dokumentace
instalace
composer require --dev phpunit/phpunit
PHPUnit - test
- třída
…Test
potomekTestCase
metoda
test…()
use PHPUnit\Framework\TestCase; class StackTest extends TestCase { public function testPushAndPop() { $stack = array(); $this->assertEquals(0, count($stack)); } }
PHPUnit - závislosti
producent, konzument
use PHPUnit\Framework\TestCase; class StackTest extends TestCase { public function testEmpty() { // ... return $stack; } #[\PHPUnit\Framework\Attributes\Depends("testEmpty")] public function testPush(array $stack) { // ... return $stack; } #[\PHPUnit\Framework\Attributes\Depends("testPush")] public function testPop(array $stack) { // ... } }
PHPUnit - zdroje dat
- opakované volání pro různé sady dat
POZOR: data provider musí být statický a public
#[\PHPUnit\Framework\Attributes\DataProvider("provider")] public function testAdd($a, $b, $c) { $this->assertEquals($c, $a + $b); } public static function provider() { return [ [0, 0, 0], [0, 1, 1], // ... ]; }
PHPUnit - výjimky
očekává se výjimka, pokud k ní nedojde je to chyba
class ExceptionTest extends TestCase { public function testException() { $this->expectException(Exception::class); } }
PHPUnit - chyby
zachycení chyby
class ExpectedErrorTest extends TestCase { public function testFailingInclude() { $this->expectException(PHPUnit\Framework\Error\Error::class); include 'not_existing_file.php'; } }
PHPUnit - assertions (tvrzení)
- (některá) tvrzení
assertCount()
assertEmpty()
assertEquals()
assertFalse()
assertTrue()
- → přehled
PHPUnit - fixtures
- prostředí, stav světa
- příprava/úklid - před každou
test…()
metodousetUp()
tearDown()
- typicky dealokace zdrojů
- sdílení zdrojů
setUpBeforeClass()
tearDownAfterClass()
- pozor na globální a statické proměnné - mohou ovlivnit testy
PHPUnit - fixtures
class StackTest extends TestCase {
protected $stack;
protected function setUp() {
$this->stack = [];
}
...
}
PHPUnit - test suite
Object Tests |-- Freezer |-- Freezer | |-- HashGenerator | |-- HashGenerator | | `-- NonRecursiveSHA1.php | | `-- NonRecursiveSHA1Test.php | |-- HashGenerator.php | | | |-- IdGenerator | |-- IdGenerator | | `-- UUID.php | | `-- UUIDTest.php | |-- IdGenerator.php | | | |-- LazyProxy.php | | | |-- Storage | |-- Storage | | `-- CouchDB.php | | `-- CouchDB | | | | |-- WithLazyLoadTest.php | | | | `-- WithoutLazyLoadTest.php | |-- Storage.php | |-- StorageTest.php | `-- Util.php | `-- UtilTest.php `-- Freezer.php `-- FreezerTest.php
PHPUnit - test suite
<phpunit>
<testsuites>
<testsuite name="Object_Freezer">
<directory>Tests</directory>
</testsuite>
</testsuites>
</phpunit>
PHPUnit - dvojníci
Testovaná jednotka závisí na jiných komponentách, které nelze použít v testovacím prostředí - nejsou dostupné, nejsou funkční, mají vedlejší efekty.
- Stub - náhradní objekt se přednastavenými návratovými hodnotami (herec)
- Mock - náhradní objekt validující chování testované jednotky (kritik)
PHPUnit - stub
class SomeClass {
public function doSomething() {
...
}
}
class StubTest extends TestCase {
public function testStub() {
$stub = $this->createStub(SomeClass::class);
$stub->method('doSomething')->willReturn('foo');
$this->assertEquals('foo', $stub->doSomething());
}
}