In der modernen Softwareentwicklung ist das Testen ein wesentlicher Bestandteil des Entwicklungsprozesses. Tests stellen sicher, dass der Code wie erwartet funktioniert und ermöglichen eine kontinuierliche Integration und Bereitstellung. Ein häufiges Szenario beim Testen ist die Notwendigkeit, externe APIs zu simulieren, um die Abhängigkeiten zu isolieren und wiederholbare Tests durchzuführen. Hier kommt WireMock ins Spiel.
WireMock ist eine flexible und leistungsstarke Java-Bibliothek, die speziell entwickelt wurde, um HTTP-APIs zu simulieren. Mit WireMock können Entwickler Mock-Server erstellen, die HTTP-Anfragen entgegennehmen und vorher definierte Antworten zurückgeben. Dies ermöglicht es, das Verhalten externer Dienste nachzubilden, ohne auf die tatsächlichen Dienste zugreifen zu müssen.
Installation und Einrichtung
Um WireMock in einem Java-Projekt zu verwenden, müssen die entsprechenden Abhängigkeiten in die Projektdatei eingefügt werden. In einem Maven-Projekt fügen wir folgende Dependency in die pom.xml
-Datei ein:
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock-jre8</artifactId>
<version>2.32.0</version>
<scope>test</scope>
</dependency>
Code-Sprache: HTML, XML (xml)
Für Gradle-Projekte wird die Dependency in die build.gradle
-Datei eingefügt:
testImplementation 'com.github.tomakehurst:wiremock-jre8:2.32.0'
Code-Sprache: JavaScript (javascript)
Nach dem Hinzufügen der Abhängigkeiten können wir mit der Verwendung von WireMock in unseren Tests beginnen.
Grundlegende Verwendung
Um WireMock in einem Test zu verwenden, müssen wir einen WireMock-Server starten, Anfragen und Antworten konfigurieren und den Server anschließend stoppen. Ein einfacher JUnit-Test mit WireMock könnte wie folgt aussehen:
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
import static com.github.tomakehurst.wiremock.client.WireMock.get;
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class WireMockTest {
private WireMockServer wireMockServer;
@BeforeEach
public void setup() {
wireMockServer = new WireMockServer(WireMockConfiguration.options().port(8080));
wireMockServer.start();
WireMock.configureFor("localhost", 8080);
}
@AfterEach
public void teardown() {
wireMockServer.stop();
}
@Test
public void testGetEndpoint() {
wireMockServer.stubFor(get(urlEqualTo("/api/test"))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody("{\"message\":\"Hello, World!\"}")));
// Hier würde der tatsächliche HTTP-Client auf den WireMock-Server zugreifen
String response = sendHttpRequest("http://localhost:8080/api/test");
assertEquals("{\"message\":\"Hello, World!\"}", response);
}
private String sendHttpRequest(String url) {
// Methode zum Senden einer HTTP-Anfrage und Rückgabe der Antwort als String
// Dies könnte beispielsweise mit HttpClient, RestTemplate oder einer anderen HTTP-Client-Bibliothek erfolgen
return ""; // Dummy-Rückgabe für das Beispiel
}
}
Code-Sprache: JavaScript (javascript)
Erklärung des Codes
- Setup und Teardown:
- In der
setup
-Methode wird ein WireMock-Server auf Port 8080 gestartet. - Die
teardown
-Methode stoppt den Server nach jedem Test. WireMock.configureFor("localhost", 8080)
konfiguriert WireMock, um auf Anfragen anlocalhost:8080
zu reagieren.
- In der
- Stubbing von Anfragen:
wireMockServer.stubFor(get(urlEqualTo("/api/test"))
definiert, dass eine GET-Anfrage an/api/test
eine vorgegebene Antwort zurückgibt.willReturn(aResponse().withStatus(200).withHeader("Content-Type", "application/json").withBody("{\"message\":\"Hello, World!\"}"))
spezifiziert die Antwort, einschließlich Statuscode, Header und Body.
- Senden einer HTTP-Anfrage:
- Die Methode
sendHttpRequest
simuliert das Senden einer HTTP-Anfrage. In einem realen Szenario würde dies durch eine HTTP-Client-Bibliothek wieHttpClient
oderRestTemplate
erfolgen.
- Die Methode
Erweiterte Funktionen
WireMock bietet eine Vielzahl von erweiterten Funktionen, die über einfache Stub-Anfragen hinausgehen. Dazu gehören:
Anfragen-Verifizierung
Neben dem Stubbing können wir auch überprüfen, ob bestimmte Anfragen während des Tests gesendet wurden:
@Test
public void testRequestVerification() {
wireMockServer.stubFor(get(urlEqualTo("/api/verify"))
.willReturn(aResponse().withStatus(200)));
sendHttpRequest("http://localhost:8080/api/verify");
WireMock.verify(WireMock.getRequestedFor(urlEqualTo("/api/verify")));
}
Code-Sprache: PHP (php)
Dynamische Antworten
WireMock unterstützt auch dynamische Antworten, die auf den eingehenden Anfragen basieren:
wireMockServer.stubFor(get(urlPathEqualTo("/api/resource"))
.withQueryParam("id", equalTo("123"))
.willReturn(aResponse()
.withStatus(200)
.withBody("{\"resource\":\"123\"}")));
Code-Sprache: PHP (php)
Simulieren von Verzögerungen und Fehlern
Um Netzwerkbedingungen oder Fehler zu simulieren, kann WireMock Verzögerungen und verschiedene Fehlerarten einfügen:
wireMockServer.stubFor(get(urlEqualTo("/api/timeout"))
.willReturn(aResponse()
.withFixedDelay(3000) // 3 Sekunden Verzögerung
.withStatus(200)
.withBody("Delayed response")));
wireMockServer.stubFor(get(urlEqualTo("/api/error"))
.willReturn(aResponse()
.withStatus(500) // Interner Serverfehler
.withBody("Internal Server Error")));
Code-Sprache: PHP (php)
Verwendung in verschiedenen Testframeworks
WireMock lässt sich nahtlos in verschiedene Testframeworks wie JUnit und TestNG integrieren. Hier ist ein Beispiel für die Verwendung mit JUnit 5:
import com.github.tomakehurst.wiremock.junit5.WireMockExtension;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.Test;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class WireMockJUnit5Test {
@RegisterExtension
static WireMockExtension wireMockExtension = WireMockExtension.newInstance()
.options(WireMockConfiguration.wireMockConfig().port(8080))
.build();
@Test
public void testWithExtension() {
stubFor(get(urlEqualTo("/api/extension"))
.willReturn(aResponse()
.withStatus(200)
.withBody("Hello from extension!")));
String response = sendHttpRequest("http://localhost:8080/api/extension");
assertEquals("Hello from extension!", response);
}
private String sendHttpRequest(String url) {
// Methode zum Senden einer HTTP-Anfrage und Rückgabe der Antwort als String
return ""; // Dummy-Rückgabe für das Beispiel
}
}
Code-Sprache: JavaScript (javascript)
Fazit
WireMock ist ein unverzichtbares Werkzeug für Entwickler, die zuverlässige und wiederholbare Tests für ihre Anwendungen erstellen möchten. Durch die Möglichkeit, externe HTTP-Dienste zu simulieren, können Tests isoliert und unabhängig von externen Systemen durchgeführt werden. Dies führt zu stabileren und aussagekräftigeren Testergebnissen.
Mit den vielfältigen Funktionen von WireMock, einschließlich der Möglichkeit, Anfragen zu stubben, zu verifizieren und dynamische Antworten zu erstellen, bietet die Bibliothek eine umfassende Lösung für das Testen von HTTP-Clients und API-Integrationen. Ob in einfachen Unit-Tests oder komplexen Integrationstests, WireMock erleichtert das Testen und trägt zur Qualitätssicherung in der Softwareentwicklung bei.