Keresés tartalomra
Kategóriák
Címkék
- Java
- Spring
- Python
- IoC
- Android
- DI
- Dagger
- Thymeleaf
- Markdown
- JDK11
- AOP
- Aspect
- Captcha
- I18n
- JavaSpark
- Microframework
- Testing
- JUnit
- Security
- JWT
- REST
- Database
- JPA
- Gépház
- WebFlux
- ReactiveProgramming
- Microservices
- Continuous Integration
- CircleCI
- Deployment Pipeline
- Docker
- Mocking
- LogProcessing
- PlantUML
- UML
- Modellezés
- OAuth2
- Node.js
- DevOps
- Websocket
Egyperces - Adatbázis újrainicializálás acceptance tesztek alatt
A Spring Boot-ra általánosan jellemző, hogy ha rábízza az alkalmazás kontextus kezelését a fejlesztő, akkor kezesbárányként fog viselkedni és nem fog meglepetéseket okozni (többnyire). Azonban a legkisebb kézi variálás is a gondosan felépített kontextus széteséséhez, vagy nem megfelelő működéséhez vezethet. Ez nincs másképp a Boot saját tesztfuttatójával sem - a @SpringBootTest
annotáció segítségével integrációs/acceptance tesztekhez húzhatjuk fel a teljes alkalmazás kontextust. Természetesen számos segédeszközt biztosít a tesztek felépítéséhez, így például a HTTP endpointokat is meghívhatjuk a tesztekből. Valószínűleg azon a ponton bukhattam el a tesztek automatikus kezelését, mikor úgy döntöttem, a Leaflet saját kliens libraryjével (Bridge) fogom végezni a HTTP hívásokat.
Na most mivel a HTTP hívások az alkalmazás egy-egy teljes flow-ját meghívják, a teszteset tranzakcionális mivolta azonnal elvész. A fura az egészben, hogy mindenesetre a tesztkontextus és az élő alkalmazás kontextus ezesetben mégis közös, a teszteset rálát az adatbázisra, azonban a tranzakcionalitását már nem tudja szabályozni. Kihasználva azonban a tényt, hogy a teszteset rálát az adatbázisra, a probléma viszonylag könnyen kiküszöbölhető. Mivel a Spring Test alapértelmezetten a JUnit-ra épül, az alább bemutatott megoldás teljesen JUnit specifikus (bár TestNG alatt is valószínűleg hasonlóképp megoldható lenne).
Szóval első lépésként a teszteseteket tartalmazó osztálynak ki kell terjesztenie a org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests
osztályt. Ez az osztály lehetővé teszi, hogy a tesztek hozzáférjenek az adatbázishoz, manipulálhassák annak tartalmát. Mindössze két metódushívásra lesz szükségünk:
private void resetDatabase() {
deleteFromTables(DATABASE_TABLES);
executeSqlScript(DATABASE_INIT_SCRIPT_LOCATION, false);
}
- deleteFromTables(String... names): ez a metódus képes törölni a paraméterként megadott táblák teljes tartalmát.
- executeSqlScript(String sqlResourcePath, boolean continueOnError): ez a metódus pedig lefuttatja a megadott SQL scriptet. A második paramétert érdemes false-ra állítani, ezzel biztosítva az adatbázis minden teszteset közben érvényes konzisztenciáját.
A teszteset végén tehát ezt a két metódust meghívva az adatbázist kvázi resetelhetjük, így megkerülve a tranzakcionalitás hiányát. Ez azonban ebben a formában nem elegáns, így segítségül hívhatjuk a JUnit MethodRule implementációit. Mindössze annyi kell, hogy a rule minden érintett teszteset végén lefusson és meghívja a fenti két metódust. Mivel a rule-nak szintén hozzá kell férnie a tesztadatbázishoz, a legegyszerűbb ha készítünk a teszteknek egy közös ősosztályt, a rule-t pedig belső osztályként definiáljuk - így az el fogja érni a fent említett metódusokat. Mivel nem minden tesztesetnél kell az adatbázist resetelni (read-only tesztek), egy egyszerű annotációval tovább finomhangolhatjuk a rule működését - ha létezik az annotáció, fusson le, különben pedig ne. Az elkészült rule implementációt már csak definiálni kell a tesztosztályban @Rule
annotációval, majd el kell látni a resetelésre utasító marker-annotációval az érintett teszteseteket.
public class ResetDatabaseRule implements MethodRule {
@Override
public Statement apply(Statement base, FrameworkMethod method, Object target) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
try {
base.evaluate();
} finally {
if (Objects.nonNull(method.getAnnotation(ResetDatabase.class))) {
resetDatabase();
}
}
}
};
}
}
Szerencsére a fenti megoldás jelentős mértékben nem lassítja a tesztfuttatást, az egyetlen zavaró tényező mindössze annyi lehet, hogy a tábla törlések és az újrainicializálás logolásra kerül - némi Logback finomhangolással persze ez a viselkedés megakadályozható.
Komment írásához jelentkezz be
Bejelentkezés
Még senki nem szólt hozzá ehhez a bejegyzéshez.