Spring MockMvc Tests mit AssertJ
Spring Framework 6.2 bzw. Spring Boot 3.4 bringt eine interessante Neuerung für Entwickler, die ihre Unit- und Integrationstests mit AssertJ schreiben: MockMvc Tests können nun auch mit AssertJ formuliert werden (GitHub Issue).
Bisher musste für Controller-Tests mit MockMvc auf die Hamcrest-Syntax zurückgegriffen werden, was zu uneinheitlichen Test-Code führen konnte.
Mit dem Release von Spring Boot 3.4 im November 2024 kann die vertraute AssertJ assertThat()
API auch in Verbindung mit MockMvc verwendet werden, was das Testen von Web-Controllern eleganter und konsistenter macht.
In diesem Artikel zeigen wir, welche Anpassungen am Code notwendig sind, um diese neue Möglichkeit nutzen zu können.
Der Code in diesem Post wurde mit Spring Boot 3.4.0-M3 getestet.
In einer Spring Boot Anwendung gibt es grundsätzlich drei Möglichkeiten, Assertions für JUnit Tests zu formulieren: mit JUnit Bordmitteln oder mittels der Libraries Hamcrest oder AssertJ.
assertEquals(a, b); // JUnit
assertThat(a, equalTo(b)); //Hamcrest
assertThat(a).isEqualTo(b); //AssertJ
Mein persönlicher Favorit ist dabei AssertJ.
Durch das Verketten von Methodenaufrufen nach assertThat
entsteht flüssig lesbarer Code.
Außerdem wird das Schreiben von Assertions durch die typabhängige Autocompletion der IDE enorm erleichtert.
Beim Testen von Spring Controllern musste man seine Assertions bisher jedoch in einem anderen Stil schreiben. Hier ein Beispiel für einen Test, der prüft, dass ein Actuator Endpunkt mit Spring Security abgesichert ist.
@SpringBootTest
@AutoConfigureMockMvc
class ActuatorTest {
@Autowired
private MockMvc mockMvc;
@Test
void actuator_health_requires_auth() {
ResultActions resultActions = mockMvc
.perform(get("/actuator/health"));
resultActions.andExpect(status().isUnauthorized());
}
}
Einstiegspunkt ist die Klasse MockMvc
, mit der wir eine Anfrage an einen Endpunkt simulieren können.
Als Ergebnis wird eine Instanz der Klasse ResultActions
zurückgegeben.
Darüber können nun mit andExpect()
Erwartungen formuliert werden.
Zugriff auf Eigenschaften der HTTP Response wird über statische Methoden aus MockMvcResultMatchers
bereitgestellt.
Mit Spring Boot 3.4 kann dieser Code mit überschaubarem Aufwand so umgeschrieben werden, dass das vertraute assertThat()
von AssertJ verwendet werden kann.
Im Wesentlichen sind dafür folgende Anpassungen vorzunehmen:
-
Aus
MockMvc
wird die neue KlasseMockMvcTester
-
Aus
ResultActions
wirdMvcTestResult
-
resultActions.andExpect(…)
wird zuassertThat(testResult)
Die größten Änderungen entstehen bei den Assertions selbst.
Hier einige Beispiele für die ResultActions
Syntax:
resultActions.andExpect(status().isOk());
resultActions.andExpect(status().isUnauthorized());
resultActions.andExpect(status().is5xxServerError());
resultActions.andExpect(content().contentTypeCompatibleWith(
MediaType.APPLICATION_JSON
);
resultActions.andExpect(jsonPath("$", contains(...)));
Und hier die Entsprechungen mit MvcTestResult
und AssertJ:
assertThat(testResult).hasStatusOk();
assertThat(testResult).hasStatus(HttpStatus.UNAUTHORIZED);
assertThat(testResult).hasStatus5xxServerError();
assertThat(testResult).hasContentTypeCompatibleWith(
MediaType.APPLICATION_JSON
);
assertThat(testResult).bodyJson().isLenientlyEqualTo("expected.json");
assertThat(testResult)
.bodyJson()
.extractingPath("$")
...
Unseren Test vom Actuator Endpunkt können wir also wie folgt umschreiben:
@SpringBootTest
@AutoConfigureMockMvc
class ActuatorTest {
@Autowired
private MockMvcTester mockMvcTester;
@Test
void actuator_health_requires_auth() {
MvcTestResult testResult = mockMvcTester
.perform(get("/actuator/health"));
assertThat(testResult).hasStatus(HttpStatus.UNAUTHORIZED);
}
}
Da der MockMvcTester
intern auf MockMvc
aufbaut, können wir uns diesen in Verbindung mit @AutoConfigureMockMvc
einfach autowiren lassen.
Wie bei MockMvc
wird auch beim MockMvcTester
ein Standalone Setup ermöglicht.
class ActuatorTest {
private final MockMvcTester mockMvc
= MockMvcTester.of(new MyController());
// ...
}
Durch ein Standalone Setup kommt man ohne Spring Context aus, wodurch die Testausführung beschleunigt wird und man näher an einem Unit-Test ist.
Über viele weitere Neuerungen seit Spring Boot 3 informieren wir in einer eigenen Schulung:
Zu den Themen Spring und Spring Boot bieten wir zudem sowohl Beratung, Entwicklungsunterstützung als auch passende Schulungen an:
Auch für Ihren individuellen Bedarf können wir Workshops und Schulungen anbieten. Sprechen Sie uns gerne an.