1. diel - Testovanie v C# .NET - Úvod do testovania
Vitajte, všetci pokročilí programátori, v online kurze testovania aplikácií v C# .NET a Visual Studio.
Kurz je tvorený najmä na základe praktických skúseností s projektmi väčšieho rozsahu. Naučíme sa v ňom postupne pokrývať kód rôznymi typmi testov a tým vytvárať spoľahlivé a kvalitné aplikácie. Je určený pre všetkých, ktorí sa usilujú o slušné zamestnanie, kde vás za tieto skúsenosti veľmi dobre ohodnotia. Alebo je určený pre tých, ktorí majú nejakú svoju aplikáciu a radi by ju ďalej pohodlne rozširovali tak, aby sa nemuseli báť, že zmeny kódu rozbijú pôvodnú funkčnosť.
Požiadavky znalostí
Budeme predpokladať, že ovládate:
- Základy programovania.
- Objektovo-orientované programovanie.
- Aspoň Základy návrhu softvéru (budeme
tu používať termíny ako use case a podobne, tak aby sme si rozumeli
).
Testovanie je vlastne takým štvrtým bodom osnovy vyššie, ktorý by mal každý dobrý programátor poznať, aby jeho práca za niečo stála.
Prečo testovať
Testovanie sa určite radí medzi dobré praktiky vývoja softvéru (best practices). Ďalšou takou praktikou je napr. programovať objektovo, používať viacvrstvovú architektúru a podobne. Niektoré praktiky by sme mali dodržiavať naozaj ortodoxne, napr. na písanie neobjektového kódu existuje naozaj jediný dôvod a tým je neznalosť programátora.
Zapuzdrovanie logiky aplikácie do objektov a vrstiev znamená pre skúseného vývojára minimálne zdržanie a minimalizuje náklady na rozširovanie a udržiavanie neprehľadnej a nerozvrstvenej aplikácie. Na druhú stranu, niektoré praktiky vývoja softvéru by sme naopak nemali dodržiavať až takto extrémne. Medzi ne patrí práve testovanie.
Kedy testovať
Hneď na úvod uvedieme, že testovanie je veľmi dôležité a v určitej časti projektu dokonca nenahraditeľné. Na druhú stranu, v prvých fázach projektu (a to najmä pri start-upoch), kedy sa hrá na čas, keď sa funkcie aplikácie často menia, a aplikáciu je potrebné čo najskôr spustiť, nie je vôbec dobrý nápad testy písať.
Museli by sa často meniť, zbytočne by zdržiavali a mohli by poškodiť rozjazd. Niektorým z vás teraz možno prebleskla hlavou teória okolo TDD (Test-Driven Development), ktorá sa naopak opiera o neustále testovanie úplne všetkého. Ako teoretický koncept znie síce pekne, ale v praxi by mal dobrý programátor dokázať myslieť aj trochu ako manažér a rozumne nakladať s vývojovým budgetom (rozpočtom). Koniec koncov, aj jeho plat vychádza z toho, ako je aplikácia konkurencieschopná. Ak máme naopak aplikáciu, ktorá má už niekoľko stabilných funkcií a chceme ju ďalej rozširovať, bez testov sa nezaobídeme.
Testami teda pokrývame také aplikácie, ktoré už majú niekoľko stabilných funkcií.
Rozširovanie softvéru
Akékoľvek rozširovanie softvéru, pokiaľ ho robíme kvalitne, vždy znamená zmenu existujúcich funkčností. Do istej miery môže kvalitná analýza a návrh pripraviť pôdu pre budúce úpravy, ale aj keď sa budeme veľa snažiť, trh sa mení nekontrolovane a úspešnú aplikáciu bude potrebné upravovať zo všetkých strán. Ak existujúce funkcie nebudeme upravovať, začne nám vznikať redundantný kód (napr. napíšeme podobnú metódu znova, namiesto toho, aby sme len parametrizovali nejakú, čo už aplikácia má, pridávame zbytočne ďalšie databázové tabuľky namiesto toho, aby sme len upravili dátový model a podobne).
Asi vieme, že vyhýbať sa úprave existujúceho kódu aplikácie sa vôbec neoplatí. Trpel by tým jej návrh a do budúcna by bolo veľmi ťažké taký zlepenec nejako upravovať alebo rozširovať, keď by sme museli zmeny vykonávať na niekoľkých miestach, bloky kódu by sa opakovali a podobne. Došli sme teda k tomu, že svoju aplikáciu budeme stále meniť a prepisovať, takto vývoj softvéru jednoducho vyzerá. A kto potom otestuje, že všetko funguje? Človek? Keď sme došli k tomu, že musíme testovať, či sa predchádzajúca funkčnosť novou úpravou nerozbila, povedzme si, prečo nemôže testovanie vykonávať človek.
Prečo to nemôže testovať človek?
Zamyslime sa nad naivnou predstavou.
Očakávania
Programátor alebo tester si sadne k počítaču a preklikne jednu službu, potom druhú a skontroluje, či fungujú. Zoberme si napríklad ITnetwork. Tester by sa skúsil zaregistrovať, prihlásiť sa, zmeniť si zabudnuté heslo, upraviť profil, dobiť body kreditnou kartou...
Funkčností (use casov) sú v tomto systéme stovky. Ak vás napadá, že človek by ich testoval hodiny a že preto to necháme urobiť stroj, ktorý to urobí pravdepodobne za pár minút, stále nemáte úplne pravdu. Sadnúť si a deň klikať nie je v zásade stále taký problém, testy sa píšu dlho, možno by sa to ešte aj vyplatilo. Ale...
Realita
Predstavme si, že takto testujeme aplikáciu, sme niekde v polovici testovacieho scenára a nájdeme chybu. Nedá sa napísať komentár k článku napr. kvôli zmene nejakého validátora. Chybu opravíme, úspešne pokračujeme až do konca scenára. Otestovanú aplikáciu nasadíme na produkčný server.
Ďalší deň nám príde e-mail, že nie je možné kupovať články. Po chvíli skúmania zistíme, že oprava, ktorú sme vykonali, rozbila inú funkčnosť, ktorú sme už otestovali predtým. Takto by sme mohli prísť aj o niekoľko tisíc eur, kým by nám chybu niekto nahlásil. A to sme vôbec nespomenuli katastrofické scenáre, kedy by došlo k nejakému úniku dát, zaspamovaniu používateľov a podobne.
Ak sa počas testovania vykoná oprava, musí sa celý scenár vykonať od začiatku!
A tých sa chýb obvykle nájde hneď niekoľko, takže sa celé testovanie
pretiahne až na niekoľko dní klikania. Programátor toto pravdepodobne
nevydrží a nevykoná testy starostlivo (osobne som frustráciu z vykonávania
tých istých úkonov stále dookola nikdy nezniesol
), čím dôjde k zaneseniu chyby
na produkcii.
A práve preto musí testy vykonávať stroj, ktorý celú aplikáciu prekliká obvykle maximálne za desiatky minút a môže to robiť znova a znova a znova. Preto píšeme automatické testy.

Typy testov
Zamerajme sa teraz na to, čo na aplikácii testujeme. Typov testov je hneď niekoľko. Obvykle nepokrývajú úplne všetky možné scenáre (všetky kódy). Hovoríme o percentuálnom pokrytí testami (code coverage), väčšinou kľúčových častí aplikácie. Čím väčšia aplikácia je, tým viac typov testov potrebuje a tým viac funkčnosti obvykle pokrývame. Prvé verzie menších aplikácií väčšinou naopak nepotrebujú žiadne testy alebo len tie úplne základné, napr. aby sa do nich dalo registrovať.
Popíšme si tie najzákladnejšie typy testov:
- Jednotkové testy (Unit testy) - Obvykle testujú univerzálne knižnice, nepíšeme ich pre kód špecifický pre danú aplikáciu. Jednotkové testy testujú triedy, presnejšie ich metódy, jednu po druhej. Odovzdávajú im rôzne vstupy a skúšajú, či sú ich výstupy korektné. Nemá veľmi zmysel pomocou unit testov testovať, či metóda obsahujúca databázový dopyt, ktorá je použitá v jednom kontroléri (CodeBehindu, nejakej riadiacej vrstve) vracia, čo má. Naopak dáva veľmi dobrý zmysel testovať napr. validátor telefónnych čísel, ktorý používame na 20 miestach alebo dokonca v niekoľkých aplikáciách. Takýto jednotkový test vyskúša napr. 20 rôznych správnych a nesprávnych telefónnych čísel, či validátor naozaj spozná, ktoré sú validné a ktoré nie. Unit testy sú tzv. whitebox testy, to znamená, že ich píšeme s tým, že vieme, ako testovaný kód vo vnútri funguje (vidíme dovnútra).
- Akceptačné testy - Tento typ testov je naopak úplne odbremenený od toho, ako je aplikácia vo vnútri naprogramovaná, sú to teda blackbox testy (nevidíme dovnútra). Každý test obvykle testuje určitú funkčnosť, napr. test na písanie článkov by testoval jednotlivé s tým spojené use cases (odovzdať článok na schválenie, schváliť článok, zamietnuť článok, publikovať článok ako administrátor...). Tieto testy obvykle využívajú framework Selenium, ktorý umožňuje automaticky klikať vo webovom prehliadači a simulovať internetového používateľa, ktorý našu aplikáciu používa. Týmito testami sa teda v podstate skúša špecifická logika aplikácie (databázové dopyty a podobne), testuje sa výsledok, ktorý aplikácia vygeneruje, nie priamo jej vnútorný kód.
- Integračné testy - V dnešnej dobe dosahujú aplikácie už pomerne vysokú komplexnosť a veľmi často bývajú rozdelené do niekoľkých služieb, ktoré spolu komunikujú a sú vyvíjané zvlášť. Práve integračné testy dohliadajú na to, aby do seba všetko správne zapadalo.
- Systémové testy - Aj keď aplikácia funguje dobre, na produkčnom prostredí podlieha ďalším vplyvom, s ktorými musíme tiež počítať. Napr. že by mala zvládať obsluhovať tisíc používateľov v jeden okamih. To by sme urobili záťažovým testom, ktorý patrí medzi systémové testy.
- A mnohé ďalšie...
V-model
Úvod do problematiky softvérového testovania zakončime predstavením tzv. V-modelu. Ten rozširuje známy vodopádový model vývoja softvéru, ktorý má nasledujúce fázy:
- Analýza požiadaviek.
- High-level návrh.
- Detailné špecifikácie.
- Implementácia.
Softvér sa už dávno nevyvíja postupným vykonaním týchto 4 fáz, ale iteračne, teda vykonávaním týchto fáz v krátkych časových intervaloch pre ďalšie a ďalšie časti aplikácie. V-model každej z týchto fáz priraďuje testovacia fáza (typ testov, o ktorých sme hovorili vyššie):

Vidíme, že názov v-modelu je odvodený z podoby s písmenom V.
Po implementácii overíme:
- unit testy detailnou špecifikáciou,
- integračnými testami high-level návrh,
- akceptačnými testami či fungujú všetky use casy.
V-model sa niekedy robí ešte o niekoľko poschodí vyšší, ak je aplikácia naozaj rozsiahla a vyžaduje viac typov testov (napr. ešte testy systémové).
V nasledujúcej lekcii, Testovanie v C# .NET - Úvod do unit testov, sa naučíme programovať unit testy, čo sú tie najjednoduchšie testy, ktoré overujú funkčnosť vnútorných knižníc (jednotiek) a obvykle s nimi začíname pri pokrývaní aplikácie testy.

David sa informačné technológie naučil na