Unit testing
Wikipedia: Unit testing
- slouží k testování jednotlivých částí kódu (units) – funkce, třídy, struktury
- každý projekt by měl mít sadu testů, které pokrývají celou funkčnost projektu
- jednotlivé testy by měly být izolované – pokud nějaký test selže, mělo by být snadné dohledat problematickou část kódu
- mělo by se testovat:
- všechny možné kombinace vstupních parametrů (v praxi: významné/charakteristické kombinace)
- ověřit chování pro platné vstupy
- ověřit chování pro neplatné vstupy (např. nastane výjimka)
- v praxi nelze zachytit všechny chyby pomocí testů (nelze pokrýt všechny možné kombinace parametrů, stavů systému, apod.), ale stejně můžou podstatně ulehčit vývoj kódu
- snaha automatizovat testování – to vedlo k continuous integration (např. GitLab CI, GitHub Actions)
Další typy testů
Integration (kombinace různých modulů), GUI (chování grafického rozhraní), installation (postup pro instalaci), regression (ověření předchozích bug fixů, změny konfigurace, apod.), security, atd.
Test-driven development
Vývojový cyklus podle test-driven development:
- Přidat test pro novou funkčnost
- Spustit všechny testy, nový test samozřejmě selže.
- Implementovat co nejjednodušší kód, který zajistí splnění všech testů. (V této fázi nový kód ani nemusí být obecný, může řešit jen konkrétní případ daný testem.)
- Ověřit, že všechny testy projdou bez chyb.
- Refaktorování kódu dle potřeby. V průběhu pomocí testů ověřovat, že nedošlo ke změně chování.
- příklady refaktorování:
- přesun kódu na logičtější místo
- odstranění duplicitního kódu
- přejmenování proměnných, funkcí, tříd
- rozdělení funkcí a metod na menší části (to ale často znamená přidání nového testu, neboť každá funkce či metoda by měla být testovaná samostatně)
- změna hierarchie dědičnosti mezi třídami
- příklady refaktorování:
- (volitelně) Ověřit kvalitu kódu pomocí programů jako např.
clang-tidy
aclang-format
. - (volitelně) Commitovat změny do systému pro správu kódu (např. git).
Tyto kroky se opakují pro každou novou funkčnost, kterou je třeba v programu implementovat.
Změny a testy by měly být malé a inkrementální a commitované samostatně:
- v případě selhání velkého množství testů se pak lze jednoduše vrátit k poslední funkční verzi
- v případě objevení nové chyby lze jednoduše identifikovat problematickou změnu, která ji způsobila
(např. git poskytuje metodu bisekce,
git bisect
, ukážeme si později)
Rozšířením tohoto přístupu je behavior-driven development, kde se pro specifikaci očekávaného chování používá doménově specifický jazyk.
Knihovny pro testování v C++
Existuje spousta knihoven, my použijeme Catch2, protože se nemusí složitě instalovat (poskytuje two-file variantu).