Menü Bezárás

Hogyan alkalmazzunk automatikus tesztbemenet-generálást?

Napjainkban egyre nagyobb népszerűségnek örvendenek az automatizált tesztelési módszerek mind az ipari felhasználás, mind az akadémiai kutatások esetén. A két terület között azonban láthatóan eltérő az automatizálási törekvés: míg akadémiai területen sok kutatás a tesztek előállításának automatizálását célozza meg, addig az ipari alkalmazások döntő részében az automatizálás a tesztek menedzselésére, futtatására törekszik. Jelen cikkben a két szféra közötti szakadék áthidalására történt erőfeszítéseim során nyert tapasztalatokat mutatom be.

Az akadémiai területet tekintve aktív kutatások folynak többek között az egységtesztelés terén is, hiszen a szoftverminőséget alapvetően meghatározó tesztelési szintről van szó. Az fejlesztési irányok azonban az egységtesztek előállításának vizsgálata felé mutatnak, ami magába foglalja a struktúra alapján történő származtatásukat is. Ebben az esetben a tesztelt szoftver forráskódja alapján történik a tesztek generálása, természetesen szem előtt tartva a fedettségi statisztikákat. Fontos kiemelni azonban, hogy a forráskód struktúrájának alapján nehézkes teljes teszteseteket származtatni, hiszen valójában nem vagy csak nehezen lehet megfogalmazni valós, elvárt kimeneteket.

A tesztbemenetek generálásáról

Az ide kapcsolódó kutatások tehát valójában tesztbemenet-generálással foglalkoznak, amelyekből előálló bemeneteket kiegészítve ugyanakkor tesztesetté is előléptethetünk. Bemenetek forráskód-struktúra alapján történő generálására több technika is létezik, amelyek közül az egyik legismertebb a szimbolikus végrehajtás. A módszer a kód végrehajtását egy magasabb absztrakciós szinten, szimbolikus változók segítségével végzi, a végrehajtás eredményeként pedig indirekten konkrét tesztbemenetek állnak elő.

A szimbolikus végrehajtás a működési elvéből fakadóan viszonylag sok kihívással küzd. A teljesség igénye nélkül ezek például a ciklusok kezelése, a mély bejárási tér, többszálúság ellenőrzése, környezeti interakció. Megoldásuk a legtöbb kapcsolódó kutatás témájaként szolgál jelenleg is, de a sok biztató eredmény ellenére vannak bizonyos tényezők, melyek maradéktalanul nem oldhatók meg.

A szimbolikus végrehajtást technikájának implementációjaként több eszköz is készült, habár az egyes eszközök képességei között meglehetősen nagy különbség lehet. A legismertebbek között említhető a NASA által fejlesztett Symbolic PathFinder, a Microsoft kutatórészlege által készített Pex, és a nyílt forráskódú projektként létező KLEE is. Lassan harmadik éve, hogy a Pex eszköz vizsgálatával foglalkozom, ugyanis a megvizsgált eszközök közül a Pex-et találtam a legfejlettebbnek a képességeiket összemérve. Ezt a feltételezést a későbbi tapasztalataim is alátámasztották.

A Microsoft Pex a szimbolikus végrehajtást parametrizált egységteszteken (PUT – Parameterized Unit Test) keresztül alkalmazza a tesztelni kívánt kódegységen. A PUT lehetőséget ad előfeltételek, elvárt kimenetek, izoláció és más tesztelési logika megvalósítására is. Az eszköz a PUT paraméterlistája alapján generál bemeneteket a végrehajtás során. Ezeket a bemeneteket a parametrizált tesztekbe helyettesítve konkrét tesztesetek kaphatók, melyek el is menthetők későbbi felhasználásra.

Tapasztalatok komplex rendszerekben

Az eszközt két komplex szoftverprojekten alkalmaztam tesztek előállítására a tesztbemenet-generálás segítségével. Az első egy összetett modellező eszköz volt, amelyet korai stádiumában vizsgáltam meg. A folyamat során feltérképeztem azokat a tényezőket, melyek befolyásolják a hatékony tesztgenerálást.

A Pex használatakor az első problémát az izoláció megvalósítása jelentette, ahol egységtesztelés lévén, mind a külső függőségeket, mind a fájlrendszer felé történő hívásokat le kellett választani. A komplex bejárási tér miatt azonban a hívások pontos, hely szerinti beazonosítása különösen nehéz feladat volt a bejárás átláthatatlansága miatt.

A másik probléma, amelybe beleütköztem a Pex használatának első néhány lépése során a komplex objektumok létrehozása és megfelelő állapotba történő beállítása volt. Ezt a Pex számára Factory minta segítségével lehet megadni, amelyre az egyszerű konstruktorokkal rendelkező osztályokon kívül a legtöbb esetben szükség is van. Ehhez kapcsolódóan érdemes említést tenni a dinamikusan, futási időben példányosított objektumok kezeléséről is, melyet a Pex nem tud kielégítően kezelni. A projekthez tartozó eredmények viszont bizakodásra adtak okot, hiszen az eszköz a vizsgált 136 metódushoz 371 teszteset generált, melyek körülbelül 99%-os kódblokk lefedettséget biztosítottak.

A felfedezett hibák között a következőket érdemes kiemelni: defenzív programozás hiánya (rosszindulatú bemenetek), inkonzisztens változtatások, kisebb funkcionális hiányosságok, illetve dinamikusan elérhetetlen kódrészletek. Ugyanakkor nem szabad elfeledni, hogy a pusztán kódlefedettségen alapuló szoftverellenőrzés hatékonysága egyes esettanulmányok szerint megkérdőjelezhető lehet.

Az eredmények láthatóvá tették számomra a Pex és a szimbolikus végrehajtás komplex rendszerekben történő alkalmazási lehetőségeit, így egy ipari partner segítségével egy tartalomkezelő rendszer végleges változatához is készítettem teszteket. A forráskód mérete ebben az esetben már egy nagyságrenddel nagyobb volt (10.000 LOC), így az eszköz használata több előkészületet igényelt. A vizsgálat azonban felderített több olyan hiányosságot is, melyeket a meglévő tesztkészlet nem vizsgált. Közülük is érdemes említést tenni egy biztonságtechnikai problémáról, illetve egy olyan változókezelési gondról, mely az adatkezelési réteg és az üzleti logikai réteg között okozhatott kommunikációs zavart.

A két projektből nyert tapasztalatok rámutattak arra, hogy a Pex képes lehet ipari méretű alkalmazások esetén is olyan teszteket előállítani, melyek a tesztek manuális tervezése és implementációja során kimaradtak. A generált tesztbemenetek között azonban sok esetben irrelevánsak is voltak, melyek a valós működés során nem fordulhattak elő. Ezeket a szimbolikus végrehajtás számára előfeltételek segítségével lehet megfogalmazni, amellyel ezek a bemenetek kizárhatók a generálásból.

Érdemes alkalmazni? És ha igen, akkor hogyan?

Az előzőekben az eszköz használatából nyert, saját tapasztalataimat mutattam be. Felvetődik így a kérdés, hogy új felhasználók (például tesztelő mérnökök) hogyan alkalmazhatják a gyakorlatban, illetve, hogy egyáltalán érdemes-e alkalmazni? A kérdéssel a Microsoft is foglalkozik, de több másik szimbolikus végrehajtást alkalmazó eszköz esetén is már készültek kapcsolódó esettanulmányok. A saját tapasztalataim alapján a válasz egyértelműen igenlő, azonban a mérnökök általi hatékony használathoz véleményem szerint jól meghatározott folyamatra, lépésekre, illetve támogató eszközökre lehet szükség. Az igenlő választásomat az a tény is alátámasztja, hogy a Microsoft a Visual Studio 2015-ös verziójában már Smart Unit Tests néven integráltan szállítja a Pex eszközt.

Az eszköz hatékony használatához a tesztgenerálást a fejlesztéssel párhuzamosan javasolom. Az iteratív folyamat bevezetésével elkerülhetők azok a használat során felmerülő nehézségek, melyeket a tapasztalataink között is bemutattunk (pl. példányosítás, izoláció). Az alkalmazandó lépések a tesztelő mérnök számára a következők lehetnek egy agilis fejlesztési folyamat során.

  • Specifikáció: Interfészek kidolgozása a fejlesztőkkel közösen figyelembe véve a tesztelhetőségi szempontokat.
  • Definiálás: Parametrizált egységtesztek definiálása minden vizsgálandó egység számára az AAA (Arrange-Act-Assert) mintát követve, ezen kívül pedig az izolációs környezet megtervezése (kódstruktúra elemzésével).
  • Implementáció: Mockok és csonkok, illetve orákulumok létrehozása a specifikáció alapján.
  • Végrehajtás: Objektumokat előállító Factory metódusok létrehozása, majd Pex futtatása minden parametrizált egységteszten.
  • Iteráció: Eredmények visszacsatolása a fejlesztők számára, majd ismétlődően a Pex futtatása a módosított kódon és visszajelzés.

Összegzés

Általánosságban tekintve nem csak a Pex, hanem a többi szimbolikus végrehajtást implementáló eszköz is alkalmas lehet arra, hogy csökkentsük az esetlegesen előforduló hibák számát, ezáltal a forráskód minőségét magasabb szintre emeljük. Ezen kívül az eszközök által készített tesztkészlet felhasználható a későbbiekben regressziós célokra is, hiszen a generálódott tesztek elmenthetők és behelyezhetők például folytonos integráció folyamatába is. Összefoglalva tehát elmondható, hogy a tesztbemenet-generálását kísérleti szinten érdemes lehet kipróbálni, de a fejlesztési folyamatba történő integráció körültekintést és megfelelően előkészített környezeteket igényel.

Szerző: Honfi Dávid

A szerző

Honfi Dávid
Dávid a BME mérnök informatikus mesterképzésének végzős hallgatója. Immáron három éve foglalkozik
szoftverek automatizált tesztelésével, azon belül pedig tesztgenerálással. Jelenlegi kutatásai során az akadémiai szférából származó eredmények mérnöki gyakorlatba történő átültetését vizsgálja.
Vissza