Jednotkové a integrační testy s PHPUnit
Některé prvky zdrojového kódu mohou být komplikované, nebo řešit velké množství různých variant vstupů a výstupů a jakákoliv jejich změna může mít fatální následky. Pro tyto účely se hodí automatizované testování, kterým lze s každou změnou ověřit, jestli vše funguje, jak má a zda nebylo nic narušeno.
Kód lze testovat jako celek, kdy se kontrolují právě vstupy a očekávané výstupy bez znalosti vnitřního chodu aplikace. Tomu se obvykle říká „integrační testování”, tedy kdy jsou integrovány různé prvky programu k dosažení úspěšného testu. Toho se obvykle využívá v takzvaném TDD, kdy se nejprve napíšou testy dle očekávaného chování, například na základě popisu API rozhraní a následně se řeší samotná realizace programu.
Další variantou jsou Unit testy, které řeší zcela izolovanou malou část kódu, takzvanou jednotku, kdy případné okolní prostředí je simulováno takzvanými mocky. Účelem těchto testů je ověření dané části nezávisle na okolí, což pomáhá rychle najít konkrétní místo příčiny chyby. Zároveň je tím zajištěna jistá míra kvality kódu, jelikož špatný kód je obtížně testovatelný.
Obou výše popsaných postupů lze ve světě PHP
dosáhnout nástrojem PHPUnit. Ten skvěle řeší
mnohé situace. Pro některé běžně se opakující prvky však nemá k tomu určené zkratky,
nepředpokládá využití
nette/di
, práci s SQL databází, neočekává práci se soubory a mnohé jiné prvky,
často specifické pro daný projekt nebo konkrétní DevStack. Pro tyto účely vznikl balíček
interitty/phpunit
,
který mnohá tato témata řeší.
Příklady použití a bližší popis je součástí dokumentace balíčku interitty/phpunit
.
Základní testovací scénáře BaseTestCase
Aby bylo možné jednoduše využít všech vlastností a výhod balíčku, stačí při tvorbě základních
testovacích scénářů vycházet z obecné třídy Interitty\PhpUnit\BaseTestCase
namísto obvyklé
PHPUnit\Framework\TestCase
.
Rozšířené kontroly
Součástí nástroje PHPUnit je množství výchozích
kontrol, pomocí
kterých lze testovat chování programu. Některé komplexnější kontroly lze sice sestavit z již
dostupných, je to však potenciální zdroj chyby a do určité míry se také jedná o porušení
principu DRY. Proto je balíček interitty/phpunit
doplněn o rozšiřující kontroly,
které tyto situace řeší.
Kontrola výstupu generátoru
Rychlost programu lze zvýšit použitím generátorů, které vrací výsledek funkce průběžně, tak jak jsou jednotlivé položky
výstupu k dispozici. Pro zajištění kontroly správného chování aplikace se může hodit mít možnost
ověřit, že finální výstup je shodný s očekávaným. Nejen pro tento účel byla vytvořena kontrola
assertSameContent
, která dokáže přijmout a vyhodnotit jakoukoliv iterovatelnou
datovou strukturu.
Příklady použití a bližší popis je součástí dokumentace balíčku interitty/phpunit
.
Továrny
Správné vytvoření nové instance vyžaduje často se opakující postup získání a nastavení potřebných parametrů, které se v daném kontextu obvykle opakují. Pro zjednodušení jsou zde tovární funkce, které tyto operace zjednodušují, aby byl výsledný kód testovacích scénářů přehlednější.
Vytvoření mocku abstraktní třídy
Obvykle využívaná tovární metoda createPartialMock
dokáže vytvořit objekt dané třídy použitelný
v testech a jednoznačně otestovat, které metody budou zavolány, s jakými parametry a co budou vracet.
Tato funkce však neumožňuje pracovat s abstraktní třídou. Pro tento účel byla vytvořena analogicky fungující metoda
createMockAbstract
.
Příklady použití a bližší popis je součástí dokumentace balíčku interitty/phpunit
.
Vytvoření dočasného adresáře a souboru
V mnoha okolnostech se pro určitý test může hodit mít k dispozici konkrétně nastavený adresář či soubor
s určitým obsahem. Je přinejmenším obtížné zajistit všechny možné kombinace obsahu a práv a přesně
pro tyto účely existuje rozšíření
mikey179/vfsstream
, které dokáže vytvořit v paměti virtuální systém souborů, které poslouží pro
daný test a když nejsou potřeba, jsou z paměti uvolněny. Výsledný kód je tak přehlednější a není
tvořen množstvím jednoúčelových souborů. Pro tento účel byly vytvořeny metody createTempDirectory
a createTempFile
.
Příklady použití a bližší popis je součástí dokumentace balíčku interitty/phpunit
.
Datové zdroje
Některé funkce a metody očekávají vcelku banální vstup, jakým je textový řetězec, se kterým následně pracují.
I v tak jednoduchém zadání však může být skrytý problém, například v práci s řetězci obsahujícími
diakritiku nebo speciální znaky. Pro tento účel je k dispozici výchozí datový zdroj
stringDataProvider
,
který poskytuje standardizovaný vstup pro řádné otestování. Zároveň je v takovém případě žádoucí otestovat i negativní
chování, tedy že se kód chová správně, pokud dostane i jiná data než textový řetězec, pomocí analogického datového zdroje
unsupportedStringDataProvider
. Pro úplnost je zde i datový zdroj
alreadyDefinedStringDataProvider
pro kontrolu chování „jednou nastavitelných vlastností objektu“.
Příklady použití a bližší popis je součástí dokumentace balíčku interitty/phpunit
.
Pomocné funkce
Při tvorbě jednotkových testů je občas potřeba
přistupovat a pracovat s neveřejnými metodami a vlastnostmi objektů. Proto je balíček interitty/phpunit
doplněn o pomocné
funkce callNonPublicMethod
,
getNonPublicPropertyValue
a setNonPublicPropertyValue
, které tyto části kódu zpřístupní.
Příklady použití a bližší popis je součástí
dokumentace balíčku interitty/phpunit
.
Standardní testy
Chyby se často skrývají na místech, kde by je nikdo nečekal a jedním z takových míst jsou pomocné funkce pro práci
s vlastnostmi objektu, takzvanými „gettery“, „settery“ a „checkery“. Jejich podoba a chování je obvykle standardní
a je tedy logické, že i testy těchto metod budou totožné. Balíček interitty/phpunit
je tedy doplněn o standardní testy pro tyto části kódu.
Příklady použití a bližší popis je součástí
dokumentace balíčku interitty/phpunit
.
Integrační testovací scénáře BaseIntegrationTestCase
Aby bylo možné jednoduše využít všech vlastností a výhod balíčku, stačí při tvorbě integračních testovacích scénářů,
využívajících nette/di
kontejner,
vycházet z obecné třídy Interitty\PhpUnit\BaseIntegrationTestCase
namísto obvyklé PHPUnit\Framework\TestCase
.
Příklady použití a bližší popis je součástí dokumentace balíčku interitty/phpunit
.
Databázové testovací scénáře BaseDibiTestCase
Aby bylo možné jednoduše využít všech vlastností a výhod balíčku, stačí při tvorbě databázových testovacích scénářů,
využívajících databázovou vrstvu Dibi, vycházet z obecné třídy
Interitty\PhpUnit\BaseDibiTestCase
namísto obvyklé
PHPUnit\Framework\TestCase
. Ve výchozím nastavení se využívá SQLite běžící výhradně v paměti, ale v případě potřeby jiné konfigurace je možné
využít metodu setConfig
.
Příklady použití a bližší popis je součástí dokumentace balíčku interitty/phpunit
.