Slovník pojmů

PHPUnit

Testovací framework pro PHP, který dává rychlou zpětnou vazbu o chování malých částí aplikace i o vybraných integracích.

Stručná definice

Nástroj pro automatizované ověřování PHP aplikací.

PHPUnit poskytuje testovací třídu, assertions pro porovnání očekávaného a skutečného výsledku, práci s očekávanými výjimkami a runner, který testy objeví a spustí. Výsledek běhu lze použít lokálně, v IDE i jako povinnou kontrolu v CI.

Název neznamená, že každý test spuštěný přes PHPUnit je unit test. Stejný framework může spouštět izolovaný test doménové služby, integrační test s databází, HTTP nebo feature test i test kontraktu. Typ testu určuje rozsah a použité závislosti, ne příkaz, kterým se spouští.

Použití

Kdy PHP aplikaci ověřovat automaticky

Test má ověřit konkrétní pozorovatelné pravidlo nebo spolupráci, která by se při další změně mohla porušit.

  • doménová pravidla, výpočty cen, slev, rezervací a stavů objednávek
  • hraniční stavy importu, validace a očekávané výjimky
  • repository, cache nebo HTTP integrace v testovacím prostředí
  • regrese chyby opravené v e-shopu či interním systému
  • rychlá zpětná vazba nad pull requestem v CI

Praktický příklad

Doplnění skladu podle skutečně chybějícího množství

Předpokládejme doménovou třídu ReorderQuantity s metodou forAvailableStock(int $available, int $target): int. Výpočet doplnění skladu je malé doménové pravidlo. Test ověřuje výsledek metody, nikoliv to, jaké privátní kroky kalkulátor interně provedl. Je rychlý, nemá síťové ani databázové závislosti a jde o unit test nezávisle na tom, že jej spouští PHPUnit.

Pokud by se místo samotného výpočtu ověřovalo uložení do databáze nebo odeslání požadavku marketplace, šlo by už o integrační nebo komunikační scénář. Zvolené assertions mají odpovídat právě tomuto kontraktu.

<?php

declare(strict_types=1);

use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

final class ReorderQuantityTest extends TestCase
{
    #[Test]
    public function it_orders_only_the_missing_stock(): void
    {
        $calculator = new ReorderQuantity();

        self::assertSame(12, $calculator->forAvailableStock(8, 20));
    }
}

Jak funguje

Od testovacího scénáře k výsledku běhu

Test popisuje ověřitelný příklad chování; runner ho provede opakovatelně v připraveném prostředí.

  1. Objevení testů Runner načte test suites z phpunit.xml nebo vybraný soubor, skupinu či filtr z příkazové řádky.
  2. Příprava Fixture vytvoří potřebná data a závislosti; setUp() a tearDown() mají řešit jen nezbytný společný stav.
  3. Provedení Test zavolá testovaný objekt nebo integrační hranici s konkrétními vstupy.
  4. Ověření Assertions porovnají výsledek, vedlejší efekt nebo očekávanou výjimku s kontraktem.
  5. Report a CI Runner vrátí výsledek a nenulový exit code může zastavit povinnou kontrolu v pull requestu.

Hlavní části

Test case, assertions a řízené scénáře

PHPUnit nabízí základní stavební bloky; jejich použití má vycházet z toho, jaký kontrakt se má ověřit.

Test case a assertions

Testovací třída dědí z TestCase. Metoda označená názvem test nebo atributem #[Test] ověřuje výsledek například přes assertSame(), strukturu hodnoty nebo výjimku.

Data providers

Jeden test lze spustit nad více sadami vstupů. Hodí se pro hranice validace nebo cenová pravidla, ne pro skrývání několika nesouvisejících scénářů v jedné metodě.

Suites, skupiny a konfigurace

phpunit.xml obvykle určuje bootstrap, sady testů a reporty. Skupiny a filtry zkracují lokální zpětnou vazbu, zatímco CI běžně spouští určenou úplnou sadu.

Fixtures

setUp() a tearDown() pomáhají se společnou přípravou a úklidem, ale příliš rozsáhlý společný fixture zakrývá, co test skutečně potřebuje.

Druhy testů a doubles

PHPUnit je runner; rozsah testu je samostatné rozhodnutí.

Jeden nástroj může obsloužit různé úrovně testování. Každá odhaluje jiný typ chyby a má jinou cenu provozu.

Unit test
Rychle ověřuje malou část pravidel v izolaci. Neměl by vyžadovat skutečnou síť, databázi ani celý framework.
Integrační test
Ověřuje spolupráci s reálnou nebo věrně provozovanou hranicí, například databází, Redisem nebo serializací HTTP požadavku.
Feature a contract test
Feature test sleduje uživatelskou či aplikační schopnost přes více vrstev. Contract test ověřuje dohodnuté rozhraní mezi systémy; ani jeden není automaticky unit test.
End-to-end test
Provádí cestu co nejblíže reálnému uživateli. Může být spuštěný jiným nástrojem; je pomalejší a není náhradou menších testů.
Stub, mock a fake
Stub vrací předem danou hodnotu. Mock navíc ověřuje očekávanou komunikaci. Fake je jednoduchá funkční náhrada, například paměťové úložiště; PHPUnit přímo vytváří zejména stuby a mocky.

Výhody a omezení

Dobré testy chrání chování, ne implementační detail

Přínosy

  • rychlá opakovatelná kontrola pravidel před mergem
  • regrese zachycená blízko změny
  • čitelně popsané očekávané chování pro další vývoj
  • možnost kombinovat rychlé unit testy s důležitými integračními scénáři

Časté chyby

  • mockování každého spolupracovníka a ověřování interních volání místo výsledku
  • sdílený stav mezi testy nebo závislost na pořadí spuštění
  • pomalé a nestabilní testy čekající na síť či čas
  • honba za procentem coverage bez ověření důležitých rozhodnutí

Hranice použití

Test má být tak izolovaný, jak dovoluje ověřovaný kontrakt.

Mock dává smysl, když je důležité ověřit komunikaci s portem — například že aplikace po úspěšné platbě předá objednávku k odeslání. Není dobré ho používat jen proto, aby každý objekt v testu byl nahrazený. Test příliš navázaný na počet volání a pomocné metody se rozbije i při bezpečném refaktoringu.

Code coverage ukazuje, která místa testy při běhu vykonaly; neprokazuje správnost assertions, smysluplnost scénáře ani pokrytí všech obchodních rizik. Pomalý test obvykle signalizuje příliš široký rozsah nebo neřízenou infrastrukturu, flaky test pak závod, sdílený stav či nedeterministický vstup, který je potřeba odstranit, ne jen opakovat.

Na co myslet

Co udrží testovací sadu užitečnou

Kvalitní sada se musí dát spouštět často a musí poskytovat srozumitelný důvod selhání.

  • název testu popisující pozorovatelné pravidlo nebo scénář
  • explicitní vstupy a minimum skrytého fixture
  • oddělené rychlé unit testy a cílené integrační sady
  • deterministický čas, náhodnost a testovací data
  • spuštění relevantní sady lokálně i povinně v CI
  • coverage jako orientační signál, ne metrika pro výkon vývojáře

Časté otázky

Co PHPUnit umí a co ne

Je každý test spuštěný přes PHPUnit unit test?

Ne. PHPUnit je framework a runner. Unit, integrační, feature, contract i jiné testy se liší rozsahem testovaného chování a použitými závislostmi.

Kdy použít stub a kdy mock?

Stub použijte pro řízený vstup od závislosti. Mock tehdy, když je součástí kontraktu samotná komunikace s ní, například odeslání příkazu s konkrétními údaji.

Stačí vysoké code coverage?

Ne. Coverage ukazuje vykonaný kód, ale neříká, zda assertions ověřují správné pravidlo, ani zda sada zahrnuje důležité chybové stavy a integrace.

Proč jsou některé testy pomalé nebo nespolehlivé?

Často závisejí na síti, čase, náhodě, sdílené databázi nebo pořadí. Takové vstupy je vhodné řídit, oddělit nebo pokrýt cíleným integračním prostředím.

Má PHPUnit běžet v CI?

Ano, obvykle nad určenou testovací sadou pro každý pull request. CI má selhat s čitelným reportem, ne testy pouze opakovat bez řešení nestability.

Jak testování používám v praxi

Testy propojuji se statickou a architektonickou kontrolou.

Na stránce zkušeností popisuji, jak volím unit a integrační testy pro různé druhy změn. Veřejný projekt scheduling obsahuje samostatné testovací sady.

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.