Spring TestExecutionListener
Használt technológiák: Spring Framework 4.0.4, Joda-Time 2.3, Hamcrest Date 1.0.1
Ebben a posztban három library három apró de érdekes képességét szeretném bemutatni, és hogy hogyan tudnak ezek együttműködni. A poszthoz tartozó mintakód megtalálható a GitHubon.
Nálunk gyakran van szükség arra, hogy a teszt esetek különböző dátumokkal dolgozzanak. Mivel van, hogy a tesztelendő funkció a mai napot veszi alapul, jól jön egy olyan lehetőség, hogy az aktuális időt be tudjuk állítani, és utána már könnyebb az asserteket megfogalmazni. Időgépnek nevezzük, mellyel ide-oda lehet ugrálni az időben.
A Java Date
magában nem alkalmas erre, általában egy factory metódust
szoktunk létrehozni, mely lekéri az aktuális időt. Ilyenkor figyelni
kell arra, hogy csak ezen metódus meghívásával hozzunk létre dátumot, ne
használjuk a Date
konstruktorát.
Azonban a Joda-Time, mely kibővíti a Java szerény dátumkezelési képességeit, tartalmaz ilyen lehetőséget.
Amennyiben a DateTimeUtils
setCurrentMillisOffset
metódusát hívjuk,
a rendszeridőhöz mindig hozzáad annyi ezredmásodpercet, mint amennyit
paraméterként megadtunk. Így nem mindig egy fix időt ad vissza, hanem az
időugrás után gyakorlatilag tovább “jár” az óra. Mivel pl. a DateTime
létrehozásakor is a DateTimeUtils
currentTimeMillis
metódusát
használja, annak példányosításakor is már a módosított időt kapjuk.
Nézzük tehát, hogy hogy lehet az időugrást elvégezni.
Valahol láttam, és megtetszett, hogy JUnit teszt esetre vonatkozó állításokat deklaratív módon, annotációkkal fogalmaztak meg. Kíváncsi voltam, hogy lehet ezt megvalósítani Spring Framework használatakor.
A megoldás, hogy egy TestExecutionListener
kell implementálni. Ez
deklarál különböző metódusokat, callbackeket, melyek különböző
eseményekkor lefutnak, pl. teszt osztály/metódus előtt/után, stb.
Létezik egy AbstractTestExecutionListener
absztrakt osztály is, mely
az interfész minden metódusát üres implementációval valósít meg, és a
leszármazott osztályunknak csak a megfelelő metódust kell felülírnia.
Azt szeretném tehát, ha annotációval tudnám megadni, hogy a teszt eset futtatásakor mennyi legyen az idő. Pl. a következő kódrészlettel:
Ehhez implementáljuk a megfelelő listenert. A beforeTestMethod
metódust írjuk felül, hogy minden teszt metódus futtatása előtt
ellenőrizze, hogy a metóduson van-e @TimeMachine
annotáció.
Ezen kívül már csak annyit kell tennünk, hogy a teszt osztályunkra rá
kell tenni a @TestExecutionListeners
annotációt.
Most már csak annyit szeretnék, hogy letesztelni, hogy működik-e az időgép. Írtam már a Hamcrestről, így Hamcrest matchert kerestem, és meg is találtam a Hamcrest Date projektet, mellyel hatékonyan tudunk dátumokat összehasonlítani.
Nézzük meg, hogy hogyan is néz ki a teszt metódus, azon belül is koncentráljunk az assertre.
A DateMatchers
within
metódusát használva ellenőrizhetjük, hogy két
dátum között mennyi a differencia, itt most max. 5 másodpercet adtunk
meg, feltételezve, hogy ennyi idő alatt biztos lefut a teszteset.