Itt jársz most: Kezdőlap > Alkalmazásfejlesztés > Egyperces - Adatbázis újrainicializálás acceptance tesztek alatt

Szűrő megjelenítése

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ó.

Kommentek

Komment írásához jelentkezz be
Bejelentkezés

Még senki nem szólt hozzá ehhez a bejegyzéshez.