Hét mód arra, hogyan fedezzük fel a szoftverhibákat élesítés előtt

Ha valaha is meglepődtél egy olyan hibán, ami utólag teljesen egyértelműnek tűnt, furdalhat a kíváncsiság, hogy honnan származnak a tesztötletek, és hogyan csináljunk még többet. Matt Heusser bemutat fél tucat ötletet, hogy miként adhatsz egy löketet a szoftvertesztelésnek.

A tesztelés egy képesség. Tanulható és gyakorlással fejleszthető is. Ebben a cikkben hét technika tesztelési ötletei kerülnek összegzésre, illetve további ötletek, hogy miként folytassuk.

  • Gyors támadások
  • Ekvivalencia- és határfeltételek
  • Gyakran elkövetett hibák
  • Állapotátmeneti diagramok
  • Használati esetek és a szappanopera tesztek
  • Kódalapú lefedettségi modellek
  • Regressziós és nagyvolumenű tesztelési technikák

Gatyát felkötni! Az elején kezdjük, és nagyon gyors tempóban fogunk haladni, különös figyelmet fordítva a webalapú alkalmazástesztelésnek.

1. technika: Gyors támadások

Ha nincs, vagy csak nagyon kicsi fogalmad van egy rendszerről, akkor nem ismerheted a követelményeket, így a követelmények tesztekké alakításának formális módszerei nem fognak segítségedre lenni. Ehelyett megtámadhatod a rendszert, megpróbálni hibás adatokkal pánikhelyzetbe hozni azt.

Ha egy mező kötelező, hagyd üresen. Ha a felhasználói felület egy meghatározott folyamatot ír elő, próbálj meg más útvonalat választani. Ha a beviteli mező egyértelműen szám kellene, hogy legyen, próbálj meg beírni egy szót, vagy egy akkora számot, amit a rendszer már nem képes lekezelni. Ha számokat kell használnod, akkor ki kell derítened, hogy a rendszer egész számokat vagy tizedestörteket vár. Ha szavakat kell használnod, akkor próbáld meg a Karaktertáblát használni Windows alatt (Start > Futtatás > charmap), és válassz olyan speciális karaktereket, amelyek általánosságban nem találhatók meg a billentyűzeteken.

Tipp
Nagy hívője vagyok a francia-kanadai és a spanyol karaktereknek, mivel azok ténylegesen előfordulnak az ügyfelek neveiben.

Az alapelv az, hogy próbálj olyan kombinációkat alkotni, melyekre a programozók nem számítottak az általános hibakezelés elkészítésekor. Ha egy összetett webes alkalmazáson dolgozol, próbáld meg gyorsan átméretezni a böngésző ablakot vagy gyorsan oda-vissza váltogatni a fülek között. Bejelentkező oldalon (vagy bármilyen képernyőn, ahol van elküldés gomb) nyomd meg az Enter-t és nézd meg, hogy elküldi-e az űrlapot (el kéne).

Gyors támadások rövid és tömör listájához tekintsd meg Elisabeth Hendrickson „Heurisztikus Teszt Segédletét” (http://testobsessed.com/wp-content/uploads/2011/04/testheuristicscheatsheetv1.pdf). Egy átfogóbb leírásért pedig tekintsd meg Mike Andrew és James Whittaker „Hogyan törjünk fel webhelyeket: Webalkalmazások és webes szolgáltatások biztonsági vizsgálata” című könyvét.

Erősségek

A gyors támadások technika lehetőséget ad egy futólagos rendszeranalízis lefuttatására egy igen szűkös időkeretben. Miután kész van, még specifikációk nélkül is tudsz valamit a szoftverről, így az erre áldozott idő megtérül, növelve a szakértelmed.

Ezt a képességet könnyű megtanulni, és miután némi gyakorlatra tettél szert a gyors támadásos szakaszaid során, valószínűleg feltűnik néhány hiba. Amíg a fejlesztők ezen hibák kijavításaival foglalkoznak, addig kigondolhatsz tényleges üzleti szerepeket, és belevetheted magad más technikákba, melyekről az elkövetkezendőkben írok.

Végezetül: a gyors támadások gyorsak. Segítségedre lehetnek egy gyors becsléshez. Bár nem ismerheted a követelményeket, ha a támadásaid sok hibát okoznak, akkor a programozók nem gondolnak kivételes esetekre, és az is valószínű, hogy a fő funkcióknál is hibáznak. Ha a támadásaid nem tárnak fel hibákat, akkor lehet némi bizalmad, hogy minden működik.

Hátrányok

A gyors támadásokat gyakran éri az a kritika, hogy „jelentéktelen hibákat” találnak – különösen belső alkalmazásoknál. Bár a képesség mesteri szinten való elsajátítása nagy erősség, sokan a gyors támadásokkal le is tudják a tesztelést, így bárki, aki elvégez egy kétnapos kurzust, már el is tudja végezni a munkát. De nem ez a helyzet. Olvass tovább!

2. technika: Ekvivalencia- és határfeltételek

Miután már van némi fogalmad arról, hogyan kéne a szoftvernek működnie, megismerkedsz a viselkedésre és kritériákra vonatkozó szabályokkal. Képzelj el egy szoftvert, ami a vezetőket osztályozza gépjárműbiztosítás szerint. A követelményekben szerepelhet az, hogy a 16 és 18 év közöttiek egy bizonyos arányban fizetnek, míg a 19 és 25 év közöttiek más arányban fizetnek, és így tovább. A kapott információkat könnyedén beilleszthetjük egy táblázatba, ahogy az 1. ábrán is látható. A valódi alkalmazás természetesen sokkal komplexebb lenne, de a lényeg így is érthető.

 
1.    ábra: Példa a gépjárműbiztosítás havi költségére, kor szerint
Már a táblázatra tekintve rögvest felfedezhetsz egy-két hibát:
  • Mennyit kérünk egy pontosan 45 éves személytől? Ezt nevezem a „45 éves problémának”.
  • Nem tudjuk hogy mennyit kérjünk attól, aki 91 éves, vagy idősebb. A követelmény lista a 90. évnél véget ért.

Így most 0-tól 91 éves korig minden korosztályt tesztelhetnénk – ami 91 teszteset lenne. Azonban egy valós alkalmazásban mind a 91 tesztet meg kéne szorozni a vezetők jogosítványán lévő pontokkal, kedvezmények sokaságával és talán még a biztosítás típusával, vagy egyéb változókkal is. A tesztesetek száma exponenciálisan nő, amit kombinatorikus robbanásnak nevezünk.

Az ekvivalencia osztályok szerint, „Hé haver, a táblázatban minden egyes oszlop egyforma. Elég egyszer tesztelni mindet”. Na jó, igazából nem ezt mondja, de megpróbál rámutatni, hogy egy oszlopon belül lévő adatok egyenlőek, vagy ekvivalensek lehetnek. (Értitek?) Ez az elmélet lehetővé teszi az 5, 18, 25, 35, 55, 71, 77, és 93 évesek tesztelését – így azokat, amiknek hasonlónak kell lennie, letudhatjuk 8 tesztben a 91 helyett.

Észrevettétek, hogy azt mondtam: kell lennie. Ez nem feltétlenül így van.

A határérték-tesztelés úgy működik, hogy egyesével kapja el a hibákat minden alkalommal, amikor a programozó „nagyobb mint” értékkel hasonlít össze két számot, miközben a „nagyobb vagy egyenlő”-t kellett volna használnia. A határérték tesztelés elkapja a „45 éves problémát”. Ebben a példában minden egyes ámenetet tesztelünk előtte és utána: 15, 16, 21, 22, 30, 31, stb., így minden eset le van fedve.

Erősségek

A határérték és ekvivalencia osztályok segítségével a végtelen számú teszteket egy még kezelhető méretre csökkenthetjük. És még arra is van egy mechanikájuk, hogy jelezzék a követelmények lefedettségét.

Hátrányok

Az 1. ábrán lévő „osztályok” csak annak a személynek helyesek, aki kiválasztotta őket. Nem tudhatjuk, hogy létezik-e más, „rejtett” osztály – például, ha egy időt reprezentáló numerikus szám következő alkalommal egy karakterkészletként vagy „string”-ként jelenik meg, a legtöbb számra működni fog.

Viszont, amikor összehasonlítod a 10, 11, és 12 számokat más számokkal, csak az első szám fog számítani – így a 10, 11 és a 12 az 1 és 2 közé fog esni. Cem Kaner (http://kaner.com/), a Florida Tech szoftverfejlesztő professzora ezt a „lokális optimum problémájának” nevezi – arra utalva, hogy a programozó képes a programot olyan viselkedésekre optimalizálni, melyek nem egyértelműek a dokumentációban.

3. technika: Gyakran elkövetett hibák

Emlékszel még a net fiatalkorára, amikor egy könyvet vagy valami mást próbáltál rendelni egy weboldalról, de semmi sem történt? Ismét a megrendelés gombra kattintottál. Ha szerencséd volt, két könyv jelent meg a kosaradban. Ám ha nem volt szerencséd, akkor a küszöbödön találtad őket. Ez a fajta hibázási lehetőség eléggé gyakori probléma volt – így megtanultunk tesztelni. Idővel a programozók okosabbak lettek, fejlesztették a kódjukat, és ez a fajta támadás egyre kevésbé volt hatékony. Ám rámutat valamire: egyes platformokon gyakran ugyanazok a hibák tűnnek fel újra és újra.

Egy mobilalkalmazás esetén például lefedettség hiányával találkozhatom, vagy túl sok megnyitott alkalmazással kis memóriával rendelkező készüléken. Azért használom ezeket a technikákat, mert láttam a hibáikat. Még a szoftverfejlesztő cégnél beleáshatunk a hibakereső szoftverünkbe, hogy kiderítsük a gyakori eseteket és teszteljük azokat. Idővel megtanítjuk a programozóinknak ezen hibák elkerülését vagy megakadályozását, javítva a kód minőségét, mielőtt éles környezetbe kerülne.

Erősségek

Ezen módszer lényege, hogy kiderítsük, milyen gyakori hibák fordulnak elő az adott platformon, projekten vagy csapatban; majd megpróbáljuk ismét tesztelni ezt a verziót. Ha új a csapatod, vagy korábban nem kerestetek hibákat, még mindig leírhatjátok azokat a felbukkanó hibákat, amik visszatérően „hatnak” – majd elkezdhetitek ellenőrizni őket.

Hátrányok

Az idő előrehaladtával járó potenciaveszteség mellett ez a módszer teljesen használhatatlan „fekete hattyúk” megtalálására – olyan hibák, melyek meghaladják a csapat tudását. Minél többet vállal a csapatod (új adatbázis használata, új programozási nyelvek, új csapattagok, stb.), annál kockázatosabbá válik a projekt – és ezzel egy időben válik egyre értéktelenebbé ez a módszer.

4. technika: Állapot-átmeneti diagramok

Képzeld el, hogy a felhasználód ott van valahol a rendszerben – mondjuk a bejelentkező képernyőn. Egy lépéssel már a következő helyen lehet, talán a kezdőlapján, vagy éppen egy hibaoldalon. Ha listázzuk az összes ilyen helyet és a köztük lévő linkeket, akkor úgymond megkapjuk az alkalmazás térképét. Majd ezek után készíthetünk teszteket, melyek végighaladnak a teljes alkalmazás minden egyes átmenetén. Pete Walen (http://rhythmoftesting.blogspot.com/) kollégám ezeket az átmeneteket használta – és állt elő ötletekkel – egy rendszerfelügyelő-alkalmazás projekt megvitatásakor, ami a 2. ábrán látható.

 
2. ábra: Walen rendszerfelügyelő alkalmazásának állapotdiagrammja
Több példát is lehet találni állapot-átmeneti diagrammokra - amit néha véges állapotú gépeknek neveznek - Dr. John Dalbey jegyzeteiben (http://users.csc.calpoly.edu/~jdalbey/SWE/Design/STDexamples.html), a Kaliforniai Politechnikai Egyetem szoftverfejlesztői kurzusán.

Erősségek

Az alkalmazás feltérképezése egy azonnali, erőteljes tesztötleteket tartalmazó listát eredményez. A modell tovább finomítható a csapattal való együttműködéssel, „rejtett” állapotátmenetek felderítésével, melyeket csak maga a programozó vagy a specifikáció szerzője ismerhet.

Amint megvan a térkép, megkérhetsz másokat, hogy rajzolják le a saját diagrammjaikat (nem tart túl sokáig), majd összehasonlítod ezeket a sajátoddal. A térképek közti különbségek utalhatnak a követelményekben lévő hiányokra, a szoftverben lévő hibákra, vagy legalább a csapattagok közti különböző elvárásokra.

Hátrányok

Az általad rajzolt térkép nem feltétlenül tükrözi a program működését, más szóval „a térkép nem a terület”. A 2. ábrán lévő korábbi példa megmutatja, hogy Pete az összes átmenetet tesztelte, de felfedeztek egy apró memóriatúlcsordulást pusztán egy hétvégére bekapcsolva hagyott monitorral. Egy diagram megrajzolása nem fog rámutatni ezekre a különbségekre, sőt, még a bizonyosság téves képzetét is adhatja a csapatnak.

5. technika: Használati esetek és a szappanopera tesztek

Ebben a szituációban alkalmazz olyan, a szoftverre fókuszáló használati eseteket és forgatókönyveket, melyekben egy ember szerepébe teszed. Ezzel a cserével olyan elképzelések merültek fel, hogy mit próbálna véghezvinni a szoftver emberként, ahelyett, hogy csak funkciók összességeként tekintenénk rá, mint a „megnyitás” és a „mentés”. Alistair Cockburn „Writing Effective Use Cases” (http://www.informit.com/store/product.aspx?isbn=0201702258) című könyvében részletesen leírja az eljárást, de úgy is tekinthetsz erre az ötletre, mintha a rendszer felhasználóiból kihúznád a ki, mi, és miért viselkedést, és egy leírásba foglalnád még a szoftver megírása előtt. Ezek a példák hajtják előre a követelményeket, a programozást és még a tesztelést is, és minden bizonnyal kiemelik a funkcionális programozás főbb pontjait, meghatározzák az alkalmazás számára a jóváhagyási teszteket, melyeket köznyelven írva is megért a felhasználó.

A forgatókönyvek hasonlóak, már abban tekintetben, hogy meg lehet velük határozni, miként használná valaki a rendszert. A szappanopera tesztek (http://en.wikipedia.org/wiki/Scenario_testing) valószínűtlen forgatókönyvek őrült és vad kombinációi, mint amilyeneket a TV-ben is látni.

Tipp

Egy biztosítónál azt teszteltük, hogy ha egy gyereket két nappal a korhatár-limit vége előtt regisztrálnak, aztán balesetet szenved, ami egy dollárral többe kerülne, mint a levonható összeg, ami egy nappal a „már túl késő feladni” vonalon túl lett beiktatva, majd megnézzzük, hogy a rendszer feldolgozza-e.
Mint a gyors támadásoknál, a szappanopera tesztek is egy gyors, informális becslést adnak a szoftver minőségéről. Végtére is, ha a szappanopera teszt sikeres, elég valószínű, hogy az egyszerű, közönséges esetek is működni fognak.

Erősségek

A használati esetek és forgatókönyvek hajlamosak együttműködni az üzleti vásárlókkal, és ha a követelményfelállítási folyamat részét képezik, szinte varázsütésre készít teszteseteket a követelményekből. Van értelmük, és jóváhagyási tesztek egyszerű sorát tudja biztosítani. A szappanopera tesztek több erőt biztosítanak, és képesek több teszttípust egyetlen folyamatba sűríteni.

Hátrányok

Az ilyen használati eseteken alapuló tesztek egyik beceneve a „tutyi-mutyi jóváhagyás” (http://en.wikipedia.org/wiki/Namby_Pamby), mivel nem fogják megadni azt a fajta kombinatorikus szigort, amit mondjuk egy ekvivalencia osztálytól vagy határértéktől kapnánk. Ha átfogó képet akarsz kapni ezekkel a technikákkal, valószínűleg nem fog sikerülni, csak elárasztod az üzleti felhasználókat részletekkel. A szappanopera tesztek pont az ellenkezői ennek, annyira összetettek, hogy ha valami elromlik, akkor tetemes időbe telhet megtalálni a hiba forrását.

6. technika: Kódalapú lefedettségi modellek

Képzeld el, hogy van egy fekete dobozod, amely megjegyzi a végrehajtott kód minden egyes sorát. Csak bekapcsolod, és hozzákezdesz a teszteléshez, majd annak végeztével kikapcsolod, és csak nézed, amíg kódok sorai állnak teszt nélkül („pirosan”). Ezt követően javíthatsz a piros funkciók és ágak tesztelésén. Erre vannak céleszközök, mind egységtesztelési szinten (Clover - http://www.atlassian.com/software/clover/overview), mind pedig felhasználóoldali tesztek szintjén (McCabe IQ - http://www.mccabe.com/).

A fentebb leírt szintet állításlefedettségnek nevezik, és megvannak a határai. Vegyük azt a példát, hogy van két IF-állításunk, mindkettő egy-egy sornyi kóddal. Talán le tudok futtatni egy tesztet, ami a teljes kódot lefedi, de hibákba ütközhetek, ha csak az első, második vagy egyik IF-állítás se kerül végrehajtásra. Számos egyéb mód van annak mérésére (http://en.wikipedia.org/wiki/Code_coverage), hogy mennyi kód került végrehajtásra, mint az áglefedettség (ami lefedné mind a négy esetet), vagy a döntési lefedettség (ami végigveszi az összes lehetséges OR, AND, és XOR-állítás kritériáját, hogy a döntésen belül elágazik-e).

Erősségek

A programozók szeretik a kódlefedettséget. Lehetővé teszik, hogy egy számot rendeljenek – egy valódi, kézzel fogható számot, mint például 75% -  az egységtesztjeik teljesítményéhez, és motiválhatják magukat a pontszám növelésére. Eközben a lefedetlen kódra tekintve új lehetőségekere bukkanhatunk a fejlesztések és hibák terén!

Hátrányok

A felhasználószintű lefedettségi eszközök költségesek, a programozó szintű eszközök, amik hajlamosak feltételezni, hogy a csapat automatizált egységtesztet végez, és egy folyamatos integrációs szerverrel és kellő fegyelemmel rendelkezik. Az eszköz telepítését követően a legtöbben az állításlefedettségre fókuszálnak – a legkevésbé erőteljes mérés felé. Még a döntési lefedettség sem foglalkozik olyan szituációkkal, ahol a döntés hibát tartalmaz, vagy amikor vannak más, rejtett ekvivalencia osztályok; tegyük fel egy harmadik féltől származó keretrendszer, amit az összeállított forráskódtól eltérően mérnek.

Kódlefedettségi számok használata hasznos lehet, bár a folyamatirányítás egy módjaként használva igazából növelheti a hibás viselkedést. A tapasztalatom szerint gyakorta jobb ezeket a méréseket a programozókra hagyni.

7. technika: Regressziós és nagyvolumenű tesztelési technikák

Szóval a mai verzió működik és kiadod. Ez remek! Viszont holnap egy új verzió más rizikóival találjuk szemben magunkat. Meg kell ismerkednünk az új funkciókkal, és biztosítani, hogy semmi sem hibás – már amennyire tudjuk. Biztosítani akarjuk, hogy a szoftver minősége nem fog visszaesni valami olyan miatt, ami tegnap még működött.

Az emberek sok pénzt költenek regressziós tesztelésre, a fentebb leírt korábbi tesztelési ötleteket alapul véve, újra és újra lefuttatva. Ezt általában vagy költséges felhasználókkal, vagy még költségesebb programozókkal oldják meg, akik hosszú időt töltenek el az automatikus tesztek megírásával, majd későbbi felügyeletével.

Kell lennie egy jobb megoldásnak! És gyakorta van is.

Ha az alkalmazásod utasítások egy sorát kapja, melyeket rögzíthetsz, és utána bármilyen rögzíthető eredményt produkál, akkor nagy mennyiségű adatot gyűjthetsz, elküldve azt mindkét alkalmazásnak, majd begyűjtheted és összehasonlíthatod az eredményt. Ha eltérő eredményt kapsz, akkor egy új funkciót építettél, egy hibát alkottál, vagy … valami  még érdekesebbet.

Ha nem vagy regressziósteszt párti, de azért meg tudod építeni a belső mag működésének modelljét, akkor lehetséges lehet véletlenszerű utasításokat generálni, és az aktuális eredményt összevetni a várt eredménnyel. Harry Robinson, Doug Hoffman és Cem Kaner ezen terület három szakértője, amit alkalmanként nagyvolumenű tesztautomatizálásnak neveznek. Harry Robinson-nak van erről egy remek prezentációja a Bing-nél. (http://seaspin.org/forums/storage/9/328/ETA_in_Bing_-_SeaSPIN_110301.pdf )

Erősségek

A megfelelő probléma esetén, mondjuk egy IT-bolt az adatbázisán keresztül dolgoz fel fájlokat, ez a technika igen hatásos lehet. Hasonlóképpen, ha a szállítható szoftver egy SQL-ben írt jelentés, akkor átadhatod a problémát másoknak teljesen köznyelven, hogy ők majd megírják a saját SQL-állításukat, és összehasonlítják az értékeket. Az állapot-átviteli diagrammoktól eltérően ez a megoldás az eszközökben lévő rejtett állapotok megtalálásában remekel. Egy pacemaker vagy rakétaindító esetén ezen hibák megtalálása igen fontos lehet.

Hátrányok

Egy felvevő/visszajátszó/elfogó szerkezet megépítése egy GUI számára igen költséges lehet, és nehéz lehet meghatározni, hogy az alkalmazás valóban elromlott-e, vagy csak egy kis mértékben változott. A legtöbb esetben ezek a megoldások láthatólag jól befészkelték magukat az IT/adatbázisok területén olyan cégeknél, mint a Microsoft és az AT&T, aminek köszönhetően a programozók a megszokott tesztek mellett ezekre is ügyelnek, vagy éppen olyan nagyobb hibákat találnak, amiket az üzleti logika ismerete nélkül is megértenek. Míg egyes szoftverprojektek láthatólag felkészülnek erre a megközelítésre, mások… nem. Sok időt és pénzt áldozhatsz rá, hogy kiderítsd, a te projekted hol bukik meg.

Technikák kombinálása

Az imént felsorolt technikák listájára tekintve két ijesztő trendet látok. A tesztek egy része könnyen automatizálható, akár a grafikus szint alatt lévő programozók által vagy egységtesztekkel lefedve. A tesztek másik fele pedig teljesen üzleti szemléletű, és csakis akkor tűnnek fel, ha valaki elkezdi használni az alkalmazást, papírt rak a nyomtatóba vagy az Internet Explorer egy kőkorszaki verziójában találkozik egy egyedi renderelési hibával. Az egyes tesztötletek átfedhetik egymást (lehet egy forgatókönyved, ami egy konkrét kötést tesztel), míg mások teljesen függetlenek.

Ez a cikk a tesztötletek kitalálására összpontosított. Most, hogy megvan a készlet (ami szinte semmi a lehetséges adatok és átalakítások összeségéhez képest), kapunk némi kihívást:

  • Korlátozzuk az ötleteket azokra, melyek most a legtöbb információt nyújtanak
  • Egyensúlyozzuk ki az egy óra alatt elvégezhető automatizálható tesztet és az 50, kézileg futtatható tesztet, hogy kiderítsük, mire jöttünk rá ebben az órában, és azt hogyan jelentsük

Én ezt úgy hívom, hogy a „tesztelés nagy játéka”: a kihívás, hogy hogyan osszuk be az időnket, és miként vonjuk le a következtetést egy gyakorlatilag végtelen rendszernél.

Szóval vesd bele magad a tesztelés nagy játékába és szórakozz jól!
Játssz, hogy nyerj!

MEGJEGYZÉS
Köszönettel tartozom a következő személyeknek, amiért segítettek a cikk áttekintésében: Ted Young (http://about.me/tedmyoung), Anne-Marie Charrett (http://annemariecharrett.com/), Catherine Powell (http://blog.abakas.com/), Timoth Western (https://twitter.com/#%21/Veretax) és David Greenlees (http://martialtester.wordpress.com/).

Szerző:
Matt Heusser

<< Vissza