Praktický návod

Jak psát PHPUnit testy, které mají skutečný smysl

Testuj pozorovatelné chování a důležitá rizika, ne pořadí privátních metod v implementaci.

25 minut · PHPUnit

Nejdřív stručně

Dobrý test je malá obchodní specifikace

Unit test má být rychlý a izolovaný od pomalých hranic, ale nemusí izolovat každou třídu od každé jiné třídy. Ověřuje výsledek nebo smluvenou komunikaci, která je součástí chování.

Integrační test použij tam, kde riziko vzniká skutečným SQL dotazem, mapováním ORM, serializací nebo konfigurací frameworku. Kombinace obou vrstev je užitečnější než vysoké procento coverage bez významných assertions.

Připrav si

Vyber chování, které stojí za ochranu

Začni drahými chybami a často měněnými pravidly, ne mechanickým testem každého getteru.

  • PHPUnit nainstalovaný jako dev dependency a jednu standardní cestu pro spuštění celé suite.
  • Popsaný vstup, pozorovatelný výstup a důležitá business invariant každého scénáře.
  • Oddělené suites pro unit a integrační testy s předvídatelným prostředím.
  • Možnost řídit čas, náhodu, UUID a externí hranice přes explicitní závislosti.

Kroky 1 až 3

Piš test od důvodu jeho existence

Název popíše pravidlo, tělo připraví minimum dat a assertion zkontroluje jeden souvislý výsledek.

1. Ověřuj chování ve tvaru arrange–act–assert

  1. Název testu formuluj jako scénář a očekávání, například paid_order_cannot_be_cancelled.
  2. Arrange připrav jen údaje důležité pro pravidlo, act zavolá veřejné API objektu a assert ověří výsledek, stav nebo doménovou výjimku.
  3. Test nesmí volat privátní metodu ani kopírovat produkční algoritmus. Po refaktoringu se stejným chováním má zůstat zelený.
  4. Pro hranice, ekvivalenční třídy a několik vstupů použij pojmenovaný data provider, aby byl při selhání vidět konkrétní případ.
vendor/bin/phpunit --testdox tests/Unit
Oficiální PHPUnit dokumentace k psaní testů

2. Mockuj jen skutečné hranice

  1. Stub použij, když potřebuješ řídit nepřímý vstup, například odpověď platební brány. Mock použij jen tehdy, když samotná komunikace je požadovaný výstup.
  2. Nemockuj value object, entitu ani každou interní službu. Spleť očekávání typu exactly(1) často test zamkne k nepodstatné implementaci.
  3. Čas nahraď Clock rozhraním, náhodu generátorem a externí API malým vlastním portem. Test tak zůstane deterministický.
  4. U důležitého adaptéru doplň integrační nebo kontraktní test, protože mock neumí ověřit skutečný protokol a mapování.
$gateway = $this->createStub(PaymentGateway::class);
Oficiální PHPUnit dokumentace k test doubles

3. Vrstvi testy podle rizika

  1. Čistá pravidla a value objekty ověř jednotkově. Repository testuj proti stejné databázi a constraintům jako v produkci.
  2. HTTP test pokryje důležitou cestu od requestu po response; několik end-to-end scénářů ověří kritický tok bez duplikace všech variant.
  3. Každý test vlastní data a po sobě zanechá známý stav. Nespoléhej na pořadí testů, lokální časovou zónu ani síť.
  4. Pomalé testy měř a opravuj. Paralelizuj až po odstranění sdílených souborů, portů a globální databázové identity.
vendor/bin/phpunit --testsuite=unit,integration
Oficiální PHPUnit dokumentace k organizaci testů

Krok 4

Ověř, že test opravdu chrání chybu

Zelený test může být bezcenný, pokud projde i po porušení pravidla.

  1. Dočasně rozbij podmínku

    Správný test selže s čitelným názvem a rozdílem. Potom produkční změnu vrať.

    vendor/bin/phpunit --testdox
  2. Spusť suite vícekrát a v náhodném pořadí

    Výsledek se nemění podle pořadí, času, lokálního prostředí ani zbytkových dat.

    vendor/bin/phpunit --order-by=random
  3. Proveď bezpečný refaktoring

    Změna vnitřní struktury bez změny veřejného chování nevyžaduje přepis poloviny mock očekávání.

Když to zlobí

Nejčastější chyby

Testy selhávají jen někdy

Najdi neřízený čas, random, pořadí, sdílenou databázi nebo síť. Závislost zpřístupni a nastav deterministicky.

vendor/bin/phpunit --order-by=random
Každý refaktoring rozbije desítky testů

Testy ověřují interní volání. Přesuň assertions na veřejný výsledek a mockuj jen významné outbound hranice.

Coverage je vysoká, ale regresí přibývá

Coverage neříká, zda assertion chrání pravidlo. Doplň hraniční a chybové scénáře podle rizik.

Integrační suite je příliš pomalá

Profiluj ji, omez bootstrap a fixture, používej transakční izolaci a nejlevnější testovací vrstvu, která dané riziko zachytí.

Hotovo

Testy popisují pravidla, ne implementační šum.

Unit a integrační testy teď chrání správná rizika, používají test doubles střídmě a dávají čitelnou zpětnou vazbu při regresi.

Zavolejte mi

Zavolám vám následující pracovní den mezi 9:00 a 17:00.

Můžete mi také zavolat rovnou.

+420 605 181 728

Nechte mi telefonní číslo a pošlete žádost o zpětné zavolání.

Odesláním souhlasíte se zpracováním údajů pro vyřízení žádosti.