Tartalom Integrált fejlesztés Java platformon JUnit JUnit használata Tesztelési technikák Demo 2 A specifikáció alapján teszteljük a program egyes részeit, klasszikus V-modell szerint Minden olyan metódust, amelynek működése nem triviális Ezen tesztek lefutása egymástól független, lehetőleg más személy készíti el, mint az implementációt Ezt követi az integrációs- és rendszerteszt 4 Klasszikus hibakeresési módszerek Klasszikus hibakeresési módszerek/2 Folyamatos kiírások, System.out.println() Egyszerű, nem igényel futtatókörnyezetet, külön jar-t Teleszemeteli a forráskódot Hosszú, átláthatatlan kimenet Manuális ellenőrzés szükséges a program minden lefutása esetén Debugger IDE támogatással, minden változó értéke kiolvasható A kód minden változtatása, javítása után lépésről lépésre végig kell haladni Manuálisan kell összehasonlítani itt is a kapott értékeket az elvártakkal 5 6 1
JUnit Keretrendszer tesztelés támogatására Fordítási időben csatolni kell JAR fájlt Jelenleg a 4.10-es verzió a legfrissebb Eredetileg a Smalltalk nyelvhez készült (SUnit) Java: JUnit C: CUnit C++: CPPUnit Sok más nyelvhez is JUnit használata 7 Parancssori használat IDE támogatás A JAR fájl legfrissebb változata letölthető: http://sourceforge.net/projects/junit/files/ Hozzá kell adni a classpath-hoz set CLASSPATH=%CLASSPATH%;%JUNIT_HO ME%\junit.jar El kell indítani a futtatni kívánt tesztet java org.junit.runner.junitcore test.alltests Eclipse-ben, Netbeansben beépített támogatás Külön hozzáadási lehetőség New/JUnit TestCase Külön futtatási beállítás 9 10 Teszt készítése Teszt készítése Konvenciók (nem szükséges): test mappában a teszt forráskódja Azonos package-ben mint a tesztelendő osztály Egy osztály metódusait közös osztályban teszteljük test... elnevezésű metódusok annotácó jelzi a tesztmetódust, pl.: public void addtest() { BigInteger a = new BigInteger( 11 ); BigInteger b = new BigInteger( 42 ); BigInteger c = a.add(b); asserttrue(c.tostring().equals( 53 )); 11 12 2
Helyesség ellenőrzése org.junit.assert osztály Tipikusan statikusan importálva asserttrue(boolean bool) Emellett rengeteg másik függvény (~50) Opcionális String paraméter: hibaüzenet Assert osztály assertequals([string message,]? expected,? actual) assertarrayequals([string message,]?[] expected,?[] actual) Opcionális hibaüzenet? helyén állhat tetszőleges primitív típus és Object float/doubleesetén érdemes megadni egy ε paramétert is asserttrue/assertfalse([string message,] boolean condition) assertnull/assertnotnull([string message,] Object reference) assertsame/assertnotsame([string message,] Object expected, Object actual) 13 14 AssertionError Assume Amennyiben hibás a teszt, akkor egy AssertionError keletkezik Ez az Error leszármazottja, nem ellenőrzött kivétel Nem a teszt hibája, valamilyen előfeltétel sérül Ignored lesz a teszt Failed helyett pl.: public void calculatetotalsalary() { DBConnection dbc = Database.connect(); assumenotnull(dbc); // 15 16 Kivételek tesztelése Fixture Fontos a keletkező kivételek tesztelése is Első módszer: try-catch- assert: kivétel típusára, message-ére, stb. Másik módszer: opcionális paraméter annotációhoz: (expected=indexoutofboundsexception.class) public void empty() { new ArrayList<Object>().get(0); Sok esetben szükség van bizonyos objektumok egy csoportján több művelet sikerességét is ellenőrizni, esetleg bizonyos erőforráshoz csatlakozni, majd elengedni. A különböző funkciók tesztelésére külön teszteseteket célszerű készíteni. Nem szeretnénk kódot duplikálni. Megoldás: az úgynevezett fixture használata. Minden teszteset számára ugyanaz a kiindulási környezet érhető el, és nem osztják meg egymás között a példányokat. 17 18 3
Fixture - megvalósítás private o; private dbc; public void setup() { o = new Object(); DBConnection dbc = Database.connect(); // public void teardown() { dbc.close(); //... Végrehajtási sorrend A és annotációval jelölt metódusok lefutnak minden teszteset előtt és után. Class és Class. Sorrend: Class #1... #N Class 19 20 Suite Paraméteres tesztelés Több tesztosztály egybefoglalására @RunWith(Suite.class) @Suite.SuiteClasses({ JunitTest1.class, JunitTest2.class ) public class JunitSuiteTest { //... Sok esetben szükség lehet egy teszteset elvégzésére több különböző paraméterrel pl.: határérték tesztelés Megoldás: parametrizált tesztesetek A megadott tesztesetek és paraméterek minden kombinációban (Déscartes-szorzat) lefutnak Minden esethez külön példány konstruktor híváson keresztül @RunWith(Parameterized.class) 21 22 Paraméteres tesztelés - példa @RunWith(Parameterized.class) public class CalculatorTest { double a, b; Calculator calc; public CalculatorTest(double a, double b) { this.a = a; this.b = b; public void setup() { calc = new Calculator(); public void testmultiply() { double result = calc.multiply(a, b); Assert.assertEquals(a * b, result, 0); @Parameters public static List<Object[]> parameters() { List<Object[]> params = new ArrayList<Object[]>(); params.add(new Object[] {0.0, 0.0); params.add(new Object[] {10.0, 0.0); params.add(new Object[] {10.0, 3.0); params.add(new Object[] {20.0, 4.0); return params; Tesztelési technikák 23 4
Mock objektumok Láthatósági problémák Komplex objektumok működését, viselkedését utánozzák egy bizonyos szempontból (ugyanazzal az interfésszel rendelkeznek). Az egységtesztek során sok külső objektumot nem célszerű, vagy nem lehetséges felhasználni, tipikusan: Nem determinisztikus működés (pl. aktuális idő, véletlen-szám) Nehezen reprodukálható állapotot szeretnénk tesztelni (pl. hálózati hiba) Lassú (pl. adatbázis kapcsolat) Még nem készült el Ilyen módon az aktuális egység izoláltan tesztelhetővé válik. public láthatóság értelemszerűen tudjuk tesztelni protected / package láthatóság ha a tesztosztályok is ugyanabban a package-ben vannak private láthatóság Java Reflection API getdeclaredmethods() setaccessible(true) 25 26 Demo 5