Unit, integrační a end-to-end testy: jaký je rozdíl
Unit, integrační a end-to-end test se neliší tím, který je „lepší“, ale především šířkou hranice a skutečnými částmi zapojenými do běhu. Čím je test užší, tím bývá zpětná vazba rychlejší a chyba se snáze lokalizuje; čím je širší, tím více reálných propojení může potvrdit, ale tím více příčin může mít selhání. Přesné rozlišení pomáhá rozdělit kontroly bez slepých míst a bez nákladného opakování stejných kombinací na každé úrovni.
Proč se názvy v týmech rozcházejí
„Unit“ nemusí znamenat jednu metodu a „integrační“ nemusí znamenat celý systém. Pro jeden tým je test služby s reálnou databází integrační; jiný jej nazývá komponentovým a označení integrace si nechává pro komunikaci mezi dvěma službami. Ani uživatelské rozhraní (UI) a end-to-end (E2E) nejsou synonyma: UI lze testovat izolovaně a celý koncový tok lze spustit přes API.
Také Practical Test Pyramid upozorňuje, že názvy vrstev nejsou univerzální a že konzistentní definice v týmu je důležitější než spor o jediný slovník. Proto se u každého typu ptejte na tři konkrétní věci:
- Co je předmětem testu a kudy do něj test vstupuje?
- Které spolupracující části jsou reálné a které nahrazené?
- Jaký pozorovatelný výsledek test potvrzuje?
Takový popis odhalí skutečný rozsah i tehdy, když dva týmy používají stejný název odlišně. V širší taxonomii jde o osu úrovně; druhy testování softwaru lze současně třídit také podle cíle, způsobu a doby spuštění.
Jeden e-shop, pět možných hranic
Použijme realistický příklad. E-shop má kalkulačku ceny, která pracuje s cenou položky, DPH, množstvím a kupónem. Komponenta košíku tato pravidla používá a připraví požadavek. Objednávková služba přes API uloží objednávku do databáze, požádá sklad o rezervaci a platební bránu o vytvoření platby. Webové UI umožní zákazníkovi projít checkoutem.
Požadavek říká: kupón LETO10 sníží cenu způsobilých položek o 10 %, sleva se uplatní před výpočtem DPH a výsledná částka se zaokrouhlí podle dohodnutého pravidla. Po úspěšném odeslání musí vzniknout objednávka se stejnou částkou, sklad musí rezervovat množství a zákazník se má dostat k platbě.
Jeden požadavek tak vytváří několik odlišných otázek. Počítá pravidlo všechny hraniční případy? Používá košík pravidlo správně? Zapíše databázový adaptér přesnou částku? Rozumějí si objednávka a sklad? Dokáže zákazník dokončit cestu v nasazeném systému? Každá otázka má přirozenou testovací hranici.
Unit test: malé chování v kontrolovaných podmínkách
Unit neboli jednotkový test ověřuje malou jednotku chování bez skutečné sítě, databáze, fronty zpráv nebo jiného pomalého či nedeterministického vnějšího systému. Jednotkou může být funkce, třída nebo malá skupina úzce souvisejících objektů. Hranice není dána počtem řádků kódu, ale tím, co tým považuje za jedno ucelené chování.
V našem příkladu zavolá test kalkulačku s cenou 100 eur, způsobilým kupónem a konkrétní sazbou DPH. Ověří přesný mezisoučet, daň a konečnou cenu. Další případy pokryjí neplatný kupón, nulové množství, hranici platnosti a zaokrouhlování. Hodiny lze nahradit řízeným zdrojem času, aby test nezávisel na dnešním datu.
Unit test má říci, že pravidlo je nesprávné, nikoli že se nepodařilo spustit databázi. Proto bývá rychlý, opakovatelný a vhodný pro mnoho kombinací. Stejně důležitý je jeho limit: neověřuje mapování JSON, databázový typ částky, konfiguraci DPH ani to, zda UI posílá kupón do správného pole.
Testujte pozorovatelné chování přes veřejnou hranici jednotky. Pokud test předepisuje pořadí každého interního volání, může jej neškodná refaktorizace rozbít, aniž se změní výsledek pro uživatele.
Komponentový test: celý modul, ne celý ekosystém
Komponentový test spustí větší celek a přistupuje k němu přes jeho veřejné rozhraní. U frontendového košíku může vykreslit celou komponentu, zadat kupón a ověřit zobrazenou částku, zatímco objednávkové API nahradí řízenou odpovědí. U backendové služby může spustit aplikaci přes HTTP se skutečnou interní logikou, ale sklad a platbu ponechat jako simulace.
Tato vrstva odhaluje chyby v propojení vnitřních částí komponenty: formulář sice načte kupón, ale stav nepředá kalkulačce; nebo controller nesprávně mapuje požadavek do doménového modelu. Zůstává užší než test celého nasazeného produktu, takže ji lze připravit cíleněji a selhání má menší okruh příčin.
Slovo komponenta je třeba v projektu definovat. Může znamenat vizuální prvek, balíček i samostatně nasaditelnou službu. Bez uvedení hranice název sám neříká, jakou jistotu test poskytuje.
Integrační test: důkaz na skutečné hranici
Integrační test ověřuje, že si dvě nebo více reálných částí správně předají data a chování. Úzký integrační test může zapojit objednávkovou službu a databázi: po volání repozitáře ověří částku, měnu, položky a stav uložený ve skutečné podporované databázi. Jiný spojí producenta a reálný message broker, aby prověřil název tématu, serializaci a potvrzení zprávy.
Širší integrační test může spustit objednávku i testovací instanci skladu. Ověří, že požadavek na rezervaci obsahuje správné identifikátory a že odpověď „nedostatek zásob“ přejde do správného stavu objednávky. Pokud místo skladu použije simulaci, testuje reálné HTTP chování objednávkové služby, nikoli kompatibilitu s aktuální implementací skladu.
Právě proto je třeba zapsat reálné závislosti. Databáze jiného typu, než používá produkce, může být vhodná pro část rychlých kontrol, ale nemusí odhalit rozdíly v typech, transakcích nebo SQL. Naopak spuštění každé vzdálené služby v každém testu prodraží přípravu a zvýší počet nesouvisejících selhání.
Na hranicích API doplňuje integrační testy kontraktní testování. Kontrakt ověřuje zaznamenaná očekávání klienta a poskytovatele i bez společného běhu celého systému. Nenahrazuje však test síťové konfigurace, autentizace ani reálných vedlejších účinků.
Systémový a E2E test: celek a koncová cesta
Systémový test ověřuje sestavený produkt jako celek vůči požadavku. Může vést přes veřejné API nebo UI a nemusí procházet jinými organizacemi či externími systémy. E2E test sleduje ucelený obchodní nebo uživatelský tok přes relevantní hranice od spouštěče po konečný výsledek.
V e-shopu může E2E scénář vytvořit produkt a kupón, otevřít checkout, odeslat objednávku, projít testovací platbou a ověřit stav objednávky i rezervaci skladu. Pokud platební brána neposkytuje bezpečný sandbox, může ji tým v kontrolovaném prostředí nahradit. Test pak stále prochází koncovou cestou ve vlastním systému, ale nepotvrzuje reálnou integraci s bránou; tu je třeba pokrýt samostatným testem v povolených podmínkách.
E2E poskytuje důkaz, že vybraná cesta drží pohromadě, ale selhání může způsobit UI, API, data, síť, sklad, platba nebo prostředí. Proto přes něj neprocházejte každou kombinaci kupónu. Jedna či několik reprezentativních cest potvrdí propojení, zatímco hraniční ceny patří níže. Praktický návrh nákupních cest rozebírá automatizované testování e-shopu.
Akceptační test není další synonymum. Říká, zda je splněna podmínka přijetí; podle toho, kde vznikne dostatečný důkaz, může být unit, komponentový, API i E2E.
Test doubles, stuby, fake objekty a mocky
Test double je zastřešující název pro náhradu produkční závislosti v testu. Terminologie knihoven se liší, ale užitečné je rozumět úloze náhrady:
- stub vrací předem připravené odpovědi, například platební služba vrátí zamítnutí;
- fake má zjednodušenou funkční implementaci, například úložiště v paměti;
- spy zaznamenává volání, která test později vyhodnotí;
- mock se obvykle nastaví s očekávanou interakcí a ověří, zda nastala;
- dummy pouze vyplní povinný parametr, ale test jej nepoužívá.
Náhrady dávají testu kontrolu nad chybami, časem a okrajovými stavy. Současně vytvářejí riziko: test může dokazovat pouze to, že kód spolupracuje s naší představou cizí služby. Čím důležitější je hranice, tím více je třeba simulaci doplnit kontraktem nebo úzkým testem se skutečnou implementací. Mockujte především vnější hranici a nestavte celý test na ověřování interních volání, která uživatel nepozoruje.
Porovnání bez falešné hierarchie
| Typ | Typická hranice | Reálné závislosti | Silná stránka | Hlavní limit |
|---|---|---|---|---|
| Unit | malé pravidlo nebo objekt | zpravidla bez sítě a databáze | rychlé kombinace, přesná diagnóza | nepotvrdí propojení |
| Komponenta | modul, UI komponenta nebo služba | vnitřek reálný, okolí často nahrazené | chování celku přes veřejnou hranici | pojem potřebuje místní definici |
| Integrace | jedna nebo více technických hranic | vybrané sousední části reálné | schémata, protokoly, databáze, konfigurace | náročnější příprava a izolace |
| Systém | sestavený produkt | většina vlastních částí reálná | požadavky na chování celku | širší okruh příčin selhání |
| E2E | celá vybraná cesta | relevantní řetězec podle deklarovaného rozsahu | důvěra v kritický tok | pomalejší běh, data a diagnostika |
Tabulka neurčuje pořadí důležitosti. Unit test nezastoupí integraci a E2E test nenahradí přesné pokrytí pravidla. Každý odpovídá na jinou otázku.
Jak zvolit úroveň pro konkrétní riziko
Nejprve napište tvrzení, které má test dokázat. Potom zvolte nejnižší hranici, na níž je toto tvrzení stále pravdivé:
- „Sleva a DPH se počítají správně pro všechny hranice“ patří především do unit testů.
- „Košík předá kalkulačce kupón a zobrazí výsledek“ patří do komponentového testu.
- „Objednávka se uloží v podporované databázi bez ztráty přesnosti“ vyžaduje integraci.
- „Objednávková a skladová služba si při rezervaci rozumějí“ vyžaduje kontrakt a podle rizika také reálný integrační test.
- „Zákazník dokáže objednat způsobilé zboží a dostat se k platbě“ vyžaduje reprezentativní systémový nebo E2E scénář.
Potom odstraňte zbytečné opakování. Pokud dvacet kombinací ceny spolehlivě ověřují unit testy, E2E stačí pro reprezentativní cenu a správný přenos výsledku. Neodstraňujte však kontrolu hranice jen proto, že je pravidlo pokryté níže.
Testovací pyramida je zde užitečná jako směřování k více úzkým a menšímu počtu širokých testů, nikoli jako povinný poměr. Produkt s množstvím vlastní logiky bude mít jiné rozložení než integrační aplikace nad cizími službami. Rozhodujte podle architektury, následku chyby, rychlosti zpětné vazby a ceny údržby.
Na co si dát pozor v reálné sadě
Mnoho mocků může vytvořit rychlou zelenou sadu, která nevidí chybné schéma ani konfiguraci. Mnoho širokých testů zase prodlouží běh a při společných datech způsobí nestabilitu. Test, který projde jen v určitém pořadí, neposkytuje spolehlivý důkaz; pomáhá, když si scénář připraví vlastní nezávislá testovací data a po sobě je kontrolovaně uklidí.
Pozor také na nejasný report. Název „checkout works“ neřekne, zda selhal výpočet, HTTP kontrakt nebo zobrazení. Zachovejte viditelnou hranici testu, vstup, očekávání a diagnostické údaje. Když širší test selže, mají úzké testy pomoci zúžit příčinu, nikoli pouze zopakovat stejný scénář jiným nástrojem.
Rozdělení běhů přizpůsobte zpětné vazbě. Rychlé unit a komponentové testy mohou běžet při každé změně, vybrané integrace podle dotčené oblasti a malá kritická E2E sada po nasazení. Širší regresi lze spustit v další fázi; konkrétní možnosti shrnuje článek o automatizovaných testech v CI/CD.
Co vhodné rozložení přinese
Vrstvená sada dává týmu rychlou informaci o chybném pravidle i samostatný důkaz, že klíčové hranice fungují. Snižuje potřebu procházet každou kombinaci přes drahou koncovou cestu a zároveň nepředstírá, že izolované mocky potvrdily reálné nasazení. Při selhání se snáze určí vlastník a při změně architektury je vidět, které hranice je třeba přehodnotit.
Další krok
Vyberte deset kritických scénářů a u každého vypište jednotlivá tvrzení, která dnes testujete. Ke každému doplňte hranici, reálné závislosti, použité test doubles, dobu běhu a typické příčiny selhání. Označte tvrzení, která se zbytečně opakují v E2E, i hranice, které nejsou reálně ověřené nikde. Následně přesuňte jednu skupinu kombinací na užší úroveň a ponechte jeden reprezentativní koncový scénář jako důkaz celého toku.