Testen von Enterprise-Anwendungen ist i. A. eine schwierige Angelegenheit, hat man es doch mit komplexen Anwendungen zu tun, die im Kern auf einem Injektionscontainer basieren. Man muss also entweder die zu testenden Anwendungskomponenten ohne Injektionscontainer selbst konstruieren und alle Dependencies mit Mock-Objekten versorgen oder die Anwendung im Injektionscontainer testen.
Quarkus bietet für letzteres eine erfreulich einfache Vorgehensweise an: Annotiert man eine JUnit-5-Klasse mit @QuarkusTest
, so wird einerseits eine Instanz der zu testenden Quarkus-Anwendung vor dem Einstieg in die Testmethoden gestartet (und am Ende wieder gestoppt) und andererseits ist dann die Testklasse eine CDI Bean, in die Services (im Code rechts: GreetingService
) der zu testenden Anwendung injiziert werden können. Formal stellen die Testmethoden Unit Tests dar, tatsächlich sind es aber Multi Unit Tests oder Integrationstests.
@QuarkusTest
public class GreetingServiceTest {
@Inject
GreetingService greetingService;
@Test
public void testGetGreeting() {
String greeting = greetingService.getGreeting();
assertEquals("Hello world!", greeting);
}
}
Im Test möchte man i. A. nicht mit externen Systemen arbeiten, sondern stattdessen bspw. passend vorbereitete Testdaten verwenden. Wir müssen somit Datenbanken oder REST-Api-Server „mocken“, also durch eine Testimplementierung ersetzen. Das kann in Quarkus-Tests sehr elegant mit CDI Alternatives geschehen. Dazu schreibt man eine zum zu ersetzenden Produktivservice kompatible Klasse im Test Classpath und annotiert sie mit @Alternative
:
// Produktivservice (REST Client) im Main Classpath (src/main/java/...):
@RegisterRestClient(configKey = "CountryApi")
public interface CountryApi {
@GET
@Path("alpha/{code}")
@Produces("application/json")
Country getByCode(@PathParam("code") String code);
// Mockservice im Test Classpath (src/test/java/...):
@ApplicationScoped
@RestClient
@Alternative
public class CountryApiMock implements CountryApi {
public Country getByCode(String code) {
...
Die Mock-Klasse muss für den Test noch aktiviert werden. Das könnte mit @Priority
geschehen, was dann aber für jeden Testfall Gültigkeit hätte. Für eine dedizierte Steuerung bietet Quarkus sog. Test Profiles an. In ihnen können (u. a.) CDI Alternatives aktiviert werden:
public class TestWithApiAlternative implements QuarkusTestProfile {
public Set<Class<?>> getEnabledAlternatives() {
return Set.of(CountryApiMock.class);
Annotiert man nun noch die Testklasse mit @TestProfile
, wird die zu testende Anwendung mit der aktivierten Mock-Klasse hochgefahren:
@QuarkusTest
@TestProfile(TestWithApiAlternative.class)
public class CountryServiceWithApiAlternativeTest {
Quarkus bietet noch viele weitere Features für die Unterstützung von Tests an, z. B. zusätzliche Mocking-Möglichkeiten, Dev Services oder Continuous Testing.
Wenn Sie Quarkus genauso begeistert wie mich (wovon ich mal ausgehe), dann kommen Sie doch mal zu unseren Vorträgen und Seminaren dazu!