Unit testing , někdy unit testing nebo unit testing ( angl. unit testing ) je proces v programování , který umožňuje kontrolovat správnost jednotlivých modulů zdrojového kódu programu , sad jednoho nebo více programových modulů spolu s odpovídajícími řídicími daty, postupy použití a zpracování.
Cílem je napsat testy pro každou netriviální funkci nebo metodu. To vám umožní rychle zkontrolovat, zda další změna v kódu vedla k regresi , tedy k výskytu chyb na již testovaných místech programu, a také usnadňuje detekci a odstranění takových chyb. Knihovnu použitou v projektu můžete například kdykoli aktualizovat na aktuální verzi spuštěním testů a identifikací nekompatibilit.
Cílem unit testování je izolovat jednotlivé části programu a ukázat, že tyto části fungují samostatně.
Tento typ testování obvykle provádějí programátoři .
Testování jednotek později umožňuje programátorům refaktorovat a přitom mít jistotu, že jednotka stále funguje správně ( regresní testování ). To vybízí programátory ke změně kódu, protože je snadné zkontrolovat, zda kód po změně stále funguje.
Unit testování pomáhá eliminovat pochybnosti o jednotlivých modulech a lze jej použít pro přístup k testování zdola nahoru: nejprve otestuje jednotlivé části programu a poté program jako celek.
Unit testy lze považovat za „živý dokument“ pro testovanou třídu . Klienti, kteří nevědí, jak používat tuto třídu, mohou jako příklad použít unit test.
Protože některé třídy mohou používat jiné třídy, testování jedné třídy se často rozšiřuje na příbuzné třídy. Třída například používá databázi; při psaní testu programátor zjistí, že test musí interagovat s databází. Toto je chyba, protože test nesmí překročit hranici třídy. Výsledkem je, že vývojář odebere databázové připojení a implementuje toto rozhraní pomocí vlastního falešného objektu . Výsledkem je méně soudržný kód a minimalizace závislostí v systému.
Testování softwaru je kombinatorický úkol. Například každá možná hodnota booleovské proměnné by vyžadovala dva testy, jeden pro TRUE a jeden pro FALSE. V důsledku toho bude každý řádek zdrojového kódu vyžadovat 3–5 řádků testovacího kódu.
Algoritmy jako Marching cubes nebo červeno-černý strom mají rozvětvený rozhodovací strom a ke kontrole všech možností jsou potřeba obrovské testovací sady: v jedné z implementací červeno-černého stromu z GitHubu bylo provedeno dvanáct testů pro kontrolu vkládání [1] . Ve druhém automaticky postaví 10! = 3,6 milionu permutací a zažijte je všechny [2] .
Jako každá testovací technologie ani testování jednotek neumožňuje zachytit všechny chyby programu. To ostatně vyplývá z praktické nemožnosti vysledovat všechny možné cesty provádění programu, kromě těch nejjednodušších případů.
Například v matematickém modelování . Obchodní aplikace často pracují s konečnými a spočetnými množinami, zatímco vědecké aplikace pracují se spojitými . [3] Proto je obtížné vybrat testy pro každou z větví programu, je těžké říci, zda je výsledek správný, zda je zachována přesnost atd. A v mnoha případech je kvalita modelování určena „od oka “ a poslední výsledek je zaznamenán jako „referenční“. Pokud je nalezena nesrovnalost, je nový výsledek zkontrolován ručně a je určeno, který je lepší: starý nebo nový.
Kód, který spolupracuje s porty , časovači , uživatelem a dalšími „nestabilními“ částmi systému, je extrémně obtížné testovat v izolovaném prostředí.
To ale neznamená, že unit testing je zde zcela nevhodný: nutí programátora přejít od souborů a portů například k abstraktním streamům . Díky tomu je kód obecnější (například můžete bez problémů přepínat ze souborů na síťové zásuvky ), testovatelnější (situaci „ztráty spojení“ můžete zkontrolovat napsáním streamu, který po vydání N bajtů bude simulovat nehodu; check pod Windows část funkcí převodu cesty
Je to v podstatě nestabilní část systému. Unit testy jsou navíc obvykle jednoduché, zatímco testy pro vícevláknové systémy by naopak měly být poměrně velké.
Při provádění jednotkových testů je každý z modulů testován samostatně. To znamená, že integrační chyby, systémové chyby a funkce prováděné v několika modulech nebudou detekovány. Navíc je tato technologie pro testy výkonu k ničemu. Jednotkové testování je tedy efektivnější, když se používá v kombinaci s jinými testovacími technikami.
Sklízení výhod jednotkového testování vyžaduje přísné dodržování testovací technologie v průběhu celého procesu vývoje softwaru. Je nutné vést nejen záznamy o všech provedených testech, ale také o všech změnách zdrojového kódu ve všech modulech. Pro tento účel by měl být použit systém kontroly verzí softwaru . Pokud tedy pozdější verze softwaru neprojde testem, který byl úspěšně složen dříve, bude snadné zkontrolovat varianty zdrojového kódu a chybu opravit. Musíte se také ujistit, že neúspěšné testy jsou neustále sledovány a analyzovány. Ignorování tohoto požadavku povede k lavině neúspěšných výsledků testů.
Kromě nejjednodušších případů musí testovaný objekt interagovat s jinými objekty. Tito "spolupracovníci" - stub objekty - jsou vyrobeny extrémně jednoduše: buď extrémně zjednodušené (paměť místo databáze), nebo určené pro konkrétní test a mechanické opakování výměnné relace. Problémy mohou nastat při změně protokolu výměny, v takovém případě musí stub objekty splňovat nové požadavky protokolu. [čtyři]
Je snadné ověřit, že modul funguje na vývojářském stroji. Obtížnější - to na cílovém stroji, často velmi omezené [5] .
Extrémní programování předpokládá jako jeden z postulátů použití nástrojů automatického testování jednotek. Tuto sadu nástrojů může vytvořit buď třetí strana (např. Boost.Test), nebo vývojový tým aplikace.
Extrémní programování používá testy jednotek pro vývoj řízený testy . Za tímto účelem vývojář před napsáním kódu napíše test, který odráží požadavky na modul. Je zřejmé, že test před napsáním kódu by neměl fungovat. Další proces je redukován na psaní nejkratšího kódu, který vyhovuje tomuto testu. Poté, co vývojář napíše další test, kód a tak dále mnohokrát.
Složitost psaní unit testů závisí na tom, jak je kód organizován. Silná soudržnost nebo velká oblast odpovědnosti jednotlivých entit (tříd pro objektově orientované jazyky) může testování ztížit. Stub by měly být vytvořeny pro objekty, které komunikují s vnějším světem (sítě, souborové I/O atd.). V terminologii se rozlišují „pokročilejší“ pahýly - Mock objekty , které nesou logiku. Je také snazší testovat rozdělením co největší části logiky do čistých funkcí . S vnějším světem nijak neinteragují a jejich výsledek závisí pouze na vstupních parametrech.
Je obvyklé oddělit testovací kód do samostatných adresářů. Je žádoucí, aby přidání nových testů do projektu nebylo obtížným úkolem a aby bylo možné spustit všechny testy. Některé systémy správy verzí, jako je git, podporují háčky ( anglicky hook ), pomocí kterých můžete nakonfigurovat spouštění všech testů před provedením změn. Pokud alespoň jeden z testů selže, změny nebudou potvrzeny. Lze také použít systémy kontinuální integrace .
Existují nástroje a knihovny pro testování jednotek pro většinu populárních programovacích jazyků na vysoké úrovni. Někteří z nich:
Některé jazyky mají podporu pro testování jednotek na úrovni syntaxe. To eliminuje potřebu vybrat si, na který framework se má propojit, a usnadňuje přenos kódu do jiných projektů.
Příklad takových jazyků:
Příklad kódu v jazyce D
třída ABC { this () { val = 2 ; } private int val ; public func () { val *= 2 ; } } unittest { ABC a ; a _ func (); tvrdit ( a . val > 0 && a . val < 555 ); // máte přístup k soukromé proměnné uvnitř modulu }