Bevor Software live gesetzt werden kann, ist es sinnvoll sicherzustellen, dass sie wie erwartet funktioniert und sich keine Fehler eingeschlichen haben. Wenn man für die eigenen Services allerdings Daten mit externen Partnern oder Systemen über deren APIs austauscht, ist es nicht immer einfach, dies sinnvoll vorab zu überprüfen.
Wenn etwa ein Zahlungsdienst angebunden wird, dieser allerdings kein Testsystem zur Verfügung stellt, ist es schwierig, mit dem produktiven System zu testen, da dabei echte Transaktionen ausgelöst werden würden. Außerdem lassen sich Fehlerszenarien nicht immer gezielt simulieren.
Hier kommen Mockserver ins Spiel, mit denen sich das Verhalten eines fremden Servers simulieren lässt, ohne diesen tatsächlich aufzurufen. Die selbst entwickelte Software kann dann statt einem externen System den Mockserver anbinden und ermöglicht so das Verhalten der eigenen Anwendung ohne weitere externe Abhängigkeiten zu überprüfen. Für einfache, statische Antworten lässt sich ein Mockserver recht einfach konfigurieren. Dieser Ansatz lediglich vordefinierte Antworten zu speichern, stößt in der Praxis jedoch schnell an seine Grenzen. Etwa wenn eine dynamische Generierung von Antworten mit variablen Werten erforderlich ist. Außerdem kann eine hohe Anzahl statischer Antworten schnell unübersichtlich werden und zu einem hohen Pflegeaufwand führen.
Eine Alternative dafür ist die dynamische Generierung von Antworten. Dabei werden vordefinierte Felder in einer Antwort während der Laufzeit befüllt. Vorteile sind die Wiederverwendbarkeit der Beispielantworten und ein geringerer Wartungsaufwand.
Dieser zweiteilige Artikel zeigt, wie WireMock diese Anforderungen erfüllt. Im ersten Teil wird erläutert, wie WireMock Standalone für einfache Testszenarien eingerichtet werden kann. Im zweiten Teil wird gezeigt, wie WireMock für komplexere Anwendungsfälle mithilfe eigener Implementierungen und Containerisierung erweitert werden kann.
Was ist ein Mockserver?
Ein Mockserver ist ein Werkzeug in der Softwarequalitätssicherung, das das Verhalten einer echten API (HTTP/REST) nachahmt. Er empfängt Anfragen von einer Anwendung und liefert vordefinierte Antworten zurück, ohne dass eine Verbindung zum tatsächlichen Backend bestehen muss. Dies ermöglicht isolierte Integrationstests.
WireMock kurz und knapp
WireMock ist ein etablierter Open-Source-Mockserver im Softwaretest und bei Microservices. Er simuliert HTTP-Services, damit Anwendungen ohne Abhängigkeit von echten APIs getestet werden können.
WireMock verwendet Stubs in JSON-Dateien, um definierte Anfragen und Antworten zu organisieren. Diese Dateien beschreiben z. B. HTTP-Methode, URL-Pfad und erwartete Antwort. Zusätzlich kann WireMock weitere statische Dateien einbinden, auf die in den Stubs verwiesen wird. Beim Start lädt WireMock alle Mappings und verarbeitet Anfragen entsprechend der dort definierten Stubs.
Neben der Cloud-Variante bietet WireMock eine Standalone-Version, die als ausführbare JAR-Datei bereitgestellt wird. Diese JAR lässt sich je nach Bedarf betreiben.
WireMock Setup
Auf der offiziellen Website von WireMock steht das Standalone-JAR zum Download zur Verfügung.
Ausführung:
Als Voraussetzung muss eine Java-Laufzeitumgebung (Version 11 oder höher empfohlen) installiert sein.
Das JAR wird mit folgendem Befehl aufgerufen:
java -jar ./target/wiremock-standalone.jar
Alternativ kann das JAR auch über Docker ausgeführt werden.
Minimaler Testfall
WireMock verwendet zwei zentrale Ordner für die Konfiguration:
- mappings/: enthält Stub-Definitionen in JSON (z. B. HTTP-Methode, URL, Antwortcode, Body).
- __files/: speichert externe Dateien (z. B. Templates, Binärdateien), die in Stubs referenziert werden.
Die beiden oben genannten Ordner werden bei der Ausführung der WireMock-JAR automatisch im Verzeichnis der JAR erstellt, sofern sie nicht vorhanden sind.
Beispiel für einen Stub (get-users.json) in mappings/:
{
"request": {
"method": "GET",
"url": "/users"
},
"response": {
"status": 200,
"bodyFileName": "users.json",
"headers": {
"Content-Type": "application/json"
}
}
}
Der bodyFileName-Wert (users.json) bezieht sich auf eine Datei im __files/-Ordner. Diese enthält z. B. statische Daten wie:
[
{
"name": "Julia Schneider",
"age": 28,
"location": "Brussels",
"profilePicture": ""
},
{
"name": "Markus Weber",
"age": 41,
"location": "Berlin",
"profilePicture": ""
}
]
Statt dem Wert bodyFileName könnte man auch mittels body direkt in der Stub-Definition einen Body für den Response definieren.
Ergebnis:
Wird eine Anfrage an die konfigurierte URL gesendet, gibt WireMock die definierte Antwort zurück:
GET localhost:8080/users
[
{
"name": "Julia Schneider",
"age": 28,
"location": "Brussels",
"profilePicture": ""
},
{
"name": "Markus Weber",
"age": 41,
"location": "Berlin",
"profilePicture": ""
}
]
Fehlerszenarien
Mit Stubs bietet WireMock die Möglichkeit, Fehlerszenarien in der Praxis zu simulieren. Zum Beispiel, wenn die oben genannte Webanwendung versucht, mit dem Zahlungsdienst zu kommunizieren und man simulieren will, wie sich das System verhält, falls dieser langsam antwortet oder vorübergehend nicht erreichbar ist.
In den folgenden Beispielen wird gezeigt, wie WireMock Error-Status-Codes, Timeouts und fehlerhafte Antworten erzeugen kann.
Error-Status-Code:
Das Attribut status in einem Stub liegt fest, welchen Status-Code WireMock bei dieser Antwort zurückliefert:
{
"request": {
"method": "GET",
"url": "/users/error"
},
"response": {
"status": 503,
"jsonBody": {
"error": "Service temporarily unavailable"
}
}
}
Wird eine Anfrage an die konfigurierte URL gesendet, gibt WireMock den definierten Status Code und die Antwort zurück:
GET localhost:8080/users/error
Status Code: 503 Service Unavailable
{
"error": "Service temporarily unavailable"
}
Timeouts
Ein Timeout tritt auf, wenn eine Anfrage nicht innerhalb der vorgegebenen Zeit beantwortet wird. Um diesen Fall zu simulieren, bietet WireMock die Konfigurationsmöglichkeit, Stubs mit einer Verzögerung zu versehen.
fixedDelayMilliseconds
Mit fixedDelayMilliseconds wird für einen Stub eine Verzögerung mit fester Dauer festgelegt. Als Einheit werden Millisekunden verwendet:
{
"request": {
"method": "GET",
"url": "/users/delayed"
},
"response": {
"status": 200,
"fixedDelayMilliseconds": 20000
}
}
Wenn eine Anfrage an die konfigurierte URL gesendet wird, antwortet WireMock erst nach 20 Sekunden.
Neben Verzögerungen mit fester Dauer gibt es auch die Möglichkeit, Verzögerungen mit zufälliger Dauer zu konfigurieren. Außerdem können anstelle von Verzögerungen für einzelne Stubs auch globale Verzögerungen für alle Stubs konfiguriert werden.
Fehlerhafte Antworten
WireMock bietet auch eine Fault-Enum an, mit deren Optionen fehlerhafte Antworten erzeugt werden können. Beispiele:
- EMPTY_RESPONSE: liefert eine komplett leere Antwort.
- RANDOM_DATA_THEN_CLOSE: sendet fehlerhafte Daten und schließt danach die Verbindung.
Beispiel, um eine leere Antwort zu erzeugen:
{
"request": {
"method": "GET",
"url": "/fault/empty-response"
},
"response": {
"fault": "EMPTY_RESPONSE"
}
}
Transformer
WireMock unterstützt die dynamische Generierung von Antworten durch vordefinierte Transformer. Diese ermöglichen die Manipulation der ursprünglichen Antworten (z. B. Anpassung des Headers, Setzen des Bodys).
WireMock nutzt Handlebars-Templates, um Antworten dynamisch anhand von Request-Attributen (z. B. Header, Body) zu generieren.
Aktivierung:
Der Transformer response-template wird in den Stub (get-user-message.json) eingefügt:
{
"request": {
"method": "GET",
"url": "/users/message"
},
"response": {
"status": 200,
"bodyFileName": "user-message.json",
"headers": {
"Content-Type": "application/json"
},
"transformers": [
"response-template"
]
}
}
Eine Beispiel-Response (user-message.json) könnte so aussehen:
{
"message": "Hallo, {{request.headers.User-Name}}!"
}
Funktionsweise:
- Die doppelten Klammern {{…}} folgen der Handlebars-Syntax.
- request.headers greift auf Header-Daten der Anfrage zu (z. B. User-Name).
- WireMock ersetzt Platzhalter durch Werte aus dem Request.
Flexibilität:
Das request-Objekt enthält URL, Header, Query-Parameter und Body. Damit lassen sich auch komplexe, dynamische Antworten erstellen.
Ergebnis:
Wird eine Anfrage mit dem erwarteten Header an die konfigurierte URL gesendet, gibt WireMock die definierte Antwort mit dem Wert des Headers zurück:
GET localhost:8080/users/message
User-Name: Markus Weber
{
"message": "Hallo, Markus Weber!"
}
Fazit
WireMock bietet durch seine leichtgewichtige Konfiguration eine flexible Lösung für Tests mit einem Mockserver. Es eignet sich sowohl für einfache Tests als auch für komplexere Szenarien – insbesondere für die Simulation dynamischer Antworten.
Kernvorteile:
- Wiederverwendbare Testumgebungen:
Mit Stubs lassen sich Testfälle definieren, die unabhängig von externen Services laufen.
- Simulation von Fehlerszenarien:
WireMock erlaubt es, gezielt Fehler wie Timeouts, fehlerhafte Antworten oder Error-Status-Codes zu erzeugen, um das Verhalten der Anwendung unter ungünstigen Bedingungen zu testen.
- Anpassbare Antworten:
Erweiterungen wie Response-Templates ermöglichen die dynamische Generierung von Antworten, die auf variablen Eingaben basieren.
In einem Kundenprojekt haben wir WireMock gezielt eingesetzt, um Services unabhängig von externen Partnern testen zu können. Das Ergebnis: Wir konnten Systemtests auf unserer Plattform zuverlässig durchführen und dabei eine Vielzahl von Testfällen abdecken – selbst dann, wenn partnerseitig kein Testsystem zur Verfügung stand.
Im zweiten Teil des Artikels wird gezeigt, wie ein Fat JAR zur Containerisierung erzeugt werden kann, das WireMock Standalone, Stubs, Beispielantworten und eigene, komplexere Transformer beinhaltet.

Mige Lin
Mige ist Junior Softwareentwickler bei isento.





