Zpět na seznam článků     Číst komentáře (2)     Verze pro tisk

PTWA: Testování softwaru

Autor: .cCuMiNn.   
16.2.2016

Tento text je součástí on-line testovací příručky, která pro vás na tomto serveru vzniká. Budeme rádi za vaše připomínky v komentářích a za vaši aktivní účast v doprovodných projektech.


Jak již bylo zmíněno, je dnes testování softwaru běžnou fází v životním cyklu vývoje aplikace. Pouze dostatečně otestovaná aplikace totiž dokáže splnit požadavky na jeho kvalitu a zajistí si tím své místo na trhu. Zůstává však otázkou, co si máme pod pojmem testování vlastně představit. Testování je pro mnoho lidí jakousi imaginární záležitostí bez přesně daných pravidel a vymezených mezí. Ve skutečnosti tomu tak ovšem v žádném případě není a i taková činnost, jakou je testování, má svá přesně stanovená pravidla. Vzpomeňte si například na úvodní fázi SDLC, ve které jsme shromažďovali jednotlivé požadavky zákazníka. Tento seznam požadavků společně s případy užití shromážděnými tamtéž se například stává jedním z hlavních vstupních bodů, od kterého se následně řada testů odráží. Během testování budete totiž ověřovat například to, zda se aplikace chová tak, aby všechny tyto požadavky naplnila. Jejich nesplnění bývá totiž často důvodem k nepřevzetí softwaru ze strany zákazníka.

Ověření, zda hotový software splňuje všechny definované požadavky, není ale při testování v žádném případě jediným cílem. Na otázky, co si tedy pod pojmem testování představit, kdy, co a jak testovat se proto pokusí odpovědět následující řádky.

Kdy, jak a co testovat

Testování byste v žádném případě neměli odkládat až na fázi po implementaci, která je této činnosti v SDLC vyčleněna. Je důležité si uvědomit, že čím dříve nějakou závadu odhalíte, tím snadnější, rychlejší a hlavně levnější bude její odstranění. Mnohem snadněji se bude odstraňovat závada, na kterou přijdete již v úvodních fázích SDLC, tedy ve fázi sběru požadavků nebo při návrhu aplikace, než když tuto vadu odhalíte až během implementace, nebo v horším případě až po implementaci, kdy před sebou máte hotový software. Pokud by se jednalo o závažnou chybu v obchodní logice, která má návaznost na různé další procesy, mohlo by to v nejhorším případě znamenat i to, že bude daleko levnější udělat zcela nový návrh a ten implementovat na zelené louce, než se snažit závadu odstranit postupnými úpravami jednotlivých již vytvořených součástí.

Je tedy zřejmé, že by testům neměla podléhat pouze hotová aplikace, ale v ideálním případě by se měl software testovat průběžně ve všech fázích SDLC. Tedy i v době, kdy ještě nebyla napsána jediná řádka kódu. Pokud Vám to zní divně, a říkáte si, že to přeci není možné, pak věřte, že testovat lze skutečně cokoliv, tedy nejenom hotový software, ale třeba i požadavky, návrh, dokumentaci, personál, metodiky, metriky, a spoustu dalších věcí, které mají s vývojem softwaru co dočinění.

Testování během analýzy

Již během fáze požadavků by mělo dojít k zapojení testera. Ten má totiž často poněkud odlišný pohled na celou problematiku než například analytik, který požadavky shromažďuje. Tester přesně ví, na kterých místech často dochází k chybám a dokáže díky tomu klást takové dotazy, které pomohou předejít nepříjemným situacím v budoucích fázích vývojového cyklu. Při testování je v tomto kroku nutné se pozastavit například nad případy užití a případně doplnit jeho negativní průběhy, na které se mnohdy zapomíná. Současně by se mělo ověřit, zda jsou požadavky dostatečně přesné a jednoznačné. Příkladem výstupu z testování analýzy webové diskuze, ke které byl uveden use case diagram v předchozí kapitole, by během této fáze mohlo být doplnění případů užití například o logování uživatelských aktivit, možnost prohlížení logů pro administrátory, nebo omezení počtu vložených příspěvků a počet registrací z jedné IP adresy v závislosti na čase.

Testování návrhu aplikace

Po vytvoření návrhu je opět potřeba překontrolovat, zda je návrh dostatečně přesný, jednoznačný a detailní. Nejednoznačnosti totiž mohou vést k tomu, že vývojáři budou vytvářet zcela jiný kód, než který od nich byl původně očekáván. Návrh by měl být také natolik přesný, aby na vývojáře nekladl nutnost si některé věci domýšlet. Při testování návrhu je nutné si již bez kódu představit hotovou aplikaci a procházet si nad návrhem všechny případy užití ve všech možných i nemožných variantách jejich průběhů. Je potřeba si klást otázky, zda někde nemůže koncový uživatel udělat něco, co není v návrhu podchyceno, a jaké bude mít toto chování dopady.

Testování při implementaci

Během implementace se do testování zapojují převážně sami vývojáři, kteří testují správnou funkčnost právě vyvíjených součástí. V tomto procesu je často využíváno unit testování, které vývojářům dokáže rychle poskytnout informaci o tom, zda jejich kód vrací skutečně takové výstupy, které jsou od něj očekávány.

Tyto testy se používají při ověřování správnosti výstupů u malých částí kódu, jako jsou metody nebo funkce. Unit testy nedělají nic jiného, než že volají testovaný kód s předem definovanými parametry a vrácený výsledek porovnávají s tím, který je očekáván. Pouze v případě, že funkce vrací očekávaný výsledek, dopadne test jednotky kladně. Pokud ovšem funkce vrátí jiný než očekávaný výsledek, bude výsledek testu označen za negativní.

Ukázka Unit Testu v PHPUnit
  1. class CalcTest extends PHPUnit_Framework_TestCase {
  2.     public function testDeleni()  {
  3.         $this->assertEquals(2, $this->calc->vydel(10, 5), "Chyba při dělení: 10 : 5 != 2");
  4.     }
  5. }

Mohlo by se zdát, že psaní unit testů zabere oproti manuálnímu testování mnohem více času. Jeho přednosti se ovšem v plné síle projeví ve chvíli, kdy budeme stejné testy provádět opakovaně. K potřebě opětovného otestování může dojít například ve chvíli, kdy vývojáři zanesou do programu nějaké změny. Při opakovaném manuálním testování bychom nad aplikací strávili stejný čas, který jsme mu věnovali již během prvního testování. Pokud jsme ale svůj čas při prvních testech věnovali právě psaní unit testů, stačí nyní tyto testy pouze spustit a za pár okamžiků budeme vědět, zda všechny testovací případy vrací očekávané výsledky.

Mezi další činnosti, které lze v této fázi zařadit mezi testování, by mohla patřit například analýza kódu již vytvořených součástí, která dokáže odhalit mnoho chyb ještě dříve, než je celý program zkompletován do funkčního celku. Některé chyby není dokonce možné jiným způsobem než analýzou kódu odhalit, takže by tato část testování rozhodně neměla být přehlížena.

Testování po implementaci

Přestože bylo testování prováděné v předchozích fázích neméně důležité než finální otestování hotové aplikace, přeci jen si v této životní fázi vývoje užije tester asi nejvíce. Abychom dokázali popsat, na co vše se musí tester při své práci zaměřit, vraťme se nyní k našemu jednoduchému příkladu s kalkulačkou. Běh hotové aplikace je zachycen na následujícím obrázku.

Testovaná aplikace - webová kalkulačka)

Základním funkčním požadavkem na tuto aplikaci je bez diskuze to, aby pro zadanou kombinaci vstupů vracela správné výstupy. Abychom dosáhli stoprocentního pokrytí testyb, museli bychom provést výpočty a ověřit vrácené výsledky pro všechny možné variace vstupů. Ve zkrácené podobě zachycuje jednotlivé testovací matematické příklady následující tabulka. Kompletní testy by přitom musely zahrnout také použití záporných čísel a nuly v hodnotách jednotlivých operandů. Uvedená tabulka je tedy pouze poloviční.

SčítáníOdčítáníNásobeníDělení
1 + 11 - 11 * 11 / 1
1 + 21 - 21 * 21 / 2
1 + 31 - 31 * 31 / 3
1 + ∞1 - ∞1 * ∞1 / ∞
2 + 12 - 12 * 12 / 1
2 + 22 - 22 * 22 / 2
2 + ∞2 - ∞2 * ∞2 / ∞
∞ + ∞∞ - ∞∞ * ∞∞ / ∞

Každý záznam v tabulce přitom znamená jeden testovací případ, a jak si můžete všimnout, je těchto případů uvedeno v tabulce nekonečné množství. Pokrýt testy všechny varianty a ověřit správné hodnoty výstupů proto není reálně možné. Jedna z otázek, na kterou jsme se proto v úvodní fázi SDLC snažili získat odpověď, zněla, s jak velkými čísly má vyvíjená kalkulačka pracovat. Díky tomu, že na tuto otázku známe odpověď, nebude již počet testovacích případů nekonečný. Přesto ale bude výsledná množina případů stále natolik veliká, že je z různých důvodů nebude možné všechny ověřit. Pokud by byl požadavek na naší kalkulačku takový, že má pracovat s operandy v intervalu < -999, +999 >, pak by počet případů k otestování byl roven součinu 1999 x 1999 x 4. Výsledkem by tedy bylo téměř 16 milionů testovacích případů. Během testování půjde tedy vždy o nalezení rovnováhy mezi pokrytím testy a jejich účinností.

Existuje několik metodik, jak z množiny testovacích případů vybrat pouze takové reprezentativní vzorky, které razantně sníží množství testovacích případů a přitom dokáží spolehlivě ověřit správné fungování testované součásti. Takovou metodou je například pokrytí hraničních hodnot, které použijeme na příkladu naší kalkulačky. Abychom správně pochopili pojmem hraniční hodnota, nakreslíme si nejprve osu hodnot.

Hraniční hodnoty a třídy ekvivalence

Mezi mezní hodnoty z této osy zařadíme nulu a čísla +/-999. Hodnoty na ose, které nejsou uvedeny, potom můžeme začlenit do tříd ekvivalence. První třída by zahrnovala záporná čísla v rozmezí -999 až -1, druhá číslici nula, a poslední třída kladná čísla 1 až 999. Hraničními hodnotami by v tomto případě byla čísla -999, 0 a 999. Během testů pak budeme provádět testovací případy pouze s hodnotami v blízkosti těchto hraničních hodnot. Následující tabulka již obsahuje skutečně všechny testovací případy ověřující požadavek na správnost sčítání. Pro otestování všech operátorů by bylo potřeba 324 testovacích případů (9 x 9 x 4), což je oproti celkovým 16 milionům variant zanedbatelné množství.

-999 + -999-998 + -999-2 + -999-1 + -9990 + -9991 + -9992 + -999998 + -999999 + -999
-999 + -998-998 + -998-2 + -998-1 + -9980 + -9981 + -9982 + -998998 + -998999 + -998
-999 + -2-998 + -2-2 + -2-1 + -20 + -21 + -22 + -2998 + -2999 + -2
-999 + -1-998 + -1-2 + -1-1 + -10 + -11 + -12 + -1998 + -1999 + -1
-999 + 0-998 + 0-2 + 0-1 + 00 + 01 + 02 + 0998 + 0999 + 0
-999 + 1-998 + 1-2 + 1-1 + 10 + 11 + 12 + 1998 + 1999 + 1
-999 + 2-998 + 2-2 + 2-1 + 20 + 21 + 22 + 2998 + 2999 + 2
-999 + 998-998 + 998-2 + 998-1 + 9980 + 9981 + 9982 + 998998 + 998999 + 998
-999 + 999-998 + 999-2 + 999-1 + 9990 + 9991 + 9992 + 999998 + 999999 + 999

Během provádění uvedených testovacích případů budou zjištěny hned dvě vady. Zaprvé není ošetřeno dělení nulou a pokus o tento výpočet proto končí chybovým hlášením.

Warning: Division by zero in C:\www\calc.php(6) : eval()'d code on line 1 Call Stack: 0.0003 679424 1. {main}() C:\www\calc.php:0 0.0004 681184 2. eval('$vysledek = 1/0;') C:\www\calc.php:6

Zadruhé dochází v případě násobení velkých čísel jako 999*999 k zobrazení výsledku v exponenciálním tvaru, který není uživatelsky příliš přívětivý.

Další testovací případy by měly ověřit také chování aplikace na nevalidní vstupy. Co se například stane, pokud se uživatel splete a namísto číslice nula vloží do pole znak velké ó. Testovací případy by proto měly zahrnout také vstupy, jako je některý ze znaků abecedy, speciální znak, některý bílý či nevalidní znak a prázdnou hodnotu.

Ověřit je potřeba i další požadavky, například ten na předvyplnění hodnot po výpočtu. Řekněme, že v našem případě bylo v zadání požadováno, aby se po provedeném výpočtu všechna pole předvyplnila zadanými hodnotami. Během testování pak zjistíte, že se správně předvyplňují pouze vstupní pole s jednotlivými operandy, ale operátor se vždy nastaví na sčítání, což nevyhovuje požadavku.

Z mimofunkčních požadavků bychom měli ověřit napříkad chování klávesy tabulátor, jejíž stisknutí by mělo vždy způsobit přechod na další pole. Bylo by uživatelsky velice nepřívětivé, kdyby použití tabulátoru přepínalo mezi jednotlivými prvky v jiném pořadí, než v jakém jsou tyto prvky vykresleny. Další test by pak zahrnoval například zjištění, zda dojde k odeslání formuláře po stisknutí klávesy enter a jaká bude reakce, pokud v tuto chvíli ještě nejsou vyplněna všechna pole.

Nesmíme zapomenout ani na zátěžové testy. V požadavcích jsme zjistili, kolik uživatelů bude s aplikací současně pracovat, a testováním bychom tedy měli ověřit, zda je to skutečně možné. Že například nebude docházet při plném zatížení k pádům aplikace nebo k výraznému snížení odezvy.

~

Jak vidíte, vyžadují testy i u tak jednoduché aplikace, jakou je naše kalkulačka, mnohem více času, než kolik ho bylo potřeba pro samotný vývoj. A nyní si představte mnohem složitější aplikaci, která přebírá současně více vstupů, které ještě ke všemu mohou být závislé na předchozích stavech systému. V takovém případě se již nebudeme bavit pouze o plánování testovacích případů, ale také o plánování testovacích scénářů. Testovací scénáře uvádí konkrétní po sobě jdoucí kroky, na kterých je nutné ověřit správnou funkci systému. Zahrnují například úkony nutné k tomu, abychom systém uvedli do požadovaného stavu před předáním konkrétních hodnot.

Testovací případy a scénáře mohou být vytvořeny vedoucím pracovníkem QA týmu, který má plánování testů na starosti, nebo jejich návrh může být ponechán na samotných testerech, kteří jednotlivé případy vytváří při exploratorním testování na základě svých zkušeností.

Při plánování testů mějte na zřeteli nepsané pravidlo, že by vývojáři neměli testovat svůj vlastní kód. Jedním z důvodů je skutečnost, že vývojář, který aplikaci vytvořil, ji tvořil podle zadání, kterému nemusel porozumět zcela správně. Není potom předpokládatelné, že by si během testování tento člověk najednou začal stejné zadání vysvětlovat jiným způsobem. Naproti tomu pokud bude aplikaci testovat někdo jiný, kdo zadání pochopí jinak než programátor, může být rozpor řešen ještě relativně včas. Programátor také automaticky předpokládá určité chování aplikace, neboť jej sám implementoval, a některé testy proto nemusí provést. Zaměřuje se totiž spíše na to, aby prokázal, že jeho kód pracuje správně, než aby se soustředil na takové varianty použití, které při vývoji neošetřil. Pokud se vývojář některým situacím nevěnoval již během vývoje, neboť ho jejich výskyt nenapadl, nedá se opět předpokládat, že by je řešil během testování.

Neméně důležitým faktorem je také psychologická stránka věci, kdy si vývojář nalezením chyby sám přidělává práci, protože bude muset problém odstranit a aplikaci opětovně otestovat. No a přiznejme si narovinu, koho by taková činnost potom bavila. Výjimku tvoří pouze unit testy, které by programátoři nad vyvíjeným projektem naopak spouštět měli, aby ověřili, že program skutečně vrací očekávané výsledky.


Tento text je součástí on-line testovací příručky, která pro vás na tomto serveru vzniká. Budeme rádi za vaše připomínky v komentářích a za vaši aktivní účast v doprovodných projektech.
Líbil se Vám článek?
Budeme potěšeni, pokud vás zaujme také reklamní nabídka

Social Bookmarking

     





Hodnocení/Hlasovalo: 2.6/5

1  2  3  4  5    
(známkování jako ve škole)