Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Lesedauer 16 Min.

Effizientes Mocking für .NET

Das Mocking von APIs ist ein wichtiger Aspekt beim Testen. Die Bibliothek WireMock.NET bietet dazu zahlreiche Funktionen an und verspricht einen schnellen Einstieg.
© dotnetpro
Die Fähigkeit, externe Abhängigkeiten effizient zu simulieren, ist in Softwareprojekten von entscheidender Bedeutung. Dies gilt insbesondere für Anwendungen, die auf externe Dienste und APIs angewiesen sind. Hier kommt WireMock.NET ins Spiel, eine leistungsstarke .NET-Bibliothek, die es ermöglicht, HTTP-basierte Services zu mocken und zu simulieren. Durch den Einsatz von WireMock.NET lassen sich realistische Testumgebungen erstellen, die das Verhalten externer Abhängigkeiten nachahmen, ohne dass diese tatsächlich verfügbar sein müssen. Dies erleichtert das Testen von Anwendungen unter verschiedenen Bedingungen und hilft dabei, potenzielle Probleme frühzeitig zu identifizieren.Die Bedeutung von WireMock.NET erstreckt sich über einfache Mocking-Funktionen hinaus. Mit erweiterten Features wie Response Templating, Stateful Behavior und der Möglichkeit, echte API-Antworten aufzuzeichnen und wiederzugeben, bietet WireMock.NET eine flexible Plattform, die komplexe Testszenarien unterstützt.Diese Episode von Frameworks und mehr behandelt daher WireMock.NET im Detail. Im Fokus stehen die Grundlagen der Bibliothek, praktische Anwendungen und erweiterte Funktionen, um zu zeigen, wie diese Bibliothek die Qualitätssicherung in der Softwareentwicklung verbessern kann.

Herausforderungen

Mocking ist in verschiedenen Bereichen der Softwareentwicklung von Bedeutung. In der Unit-Test-Phase ermöglicht es das Isolieren von Komponenten, um ihre Funktionalität ­unabhängig von externen Systemen zu überprüfen. Bei Inte­grationstests hilft Mocking, die Interaktion zwischen verschiedenen Modulen zu testen, ohne auf externe Abhängigkeiten angewiesen zu sein. In der End-to-End-Testphase lassen sich durch Mocking komplexe Anwendungsszenarien in einer kontrollierten Umgebung nachstellen, was bei der Identifizierung und Behebung von Fehlern hilft.Eine der größten Herausforderungen beim Mocking liegt in der korrekten Simulation von externen Abhängigkeiten. Es ist entscheidend, dass die Mocks das Verhalten dieser Services realistisch nachbilden, um aussagekräftige Testergebnisse zu erhalten. Dies erfordert ein tiefes Verständnis der externen Systeme sowie der Anforderungen der Anwendung, die getestet werden soll.Ein weiteres Problem ist die Aufrechterhaltung der Aktualität und Relevanz der Mocks. Externe Services entwickeln sich weiter, und Mocks sind entsprechend anzupassen, um mit diesen Änderungen Schritt zu halten. Dies kann insbesondere in agilen Entwicklungsprozessen, bei denen schnelle Iterationen und Anpassungen die Norm sind, eine Herausforderung darstellen.Mocking ist ein wesentlicher Bestandteil der Softwareentwicklung, da es die Erstellung robuster, zuverlässiger und unabhängig testbarer Anwendungen ermöglicht. Die Herausforderungen, die es mit sich bringt, sind ein kleiner Preis für die Vorteile, die es bietet.

Überblick und Grundlagen von WireMock.NET

Wie in der Einleitung kurz erwähnt, ist WireMock.NET eine flexible .NET-Bibliothek für das Mocking von HTTP-basierten Diensten. Die Bibliothek ermöglicht es, das Verhalten von Webdiensten in Tests zu simulieren, was für die Entwicklung und das Testen von Anwendungen, die auf externe HTTP-Schnittstellen angewiesen sind, unerlässlich ist. Diese Bibliothek ist besonders nützlich, um konsistente, wiederholbare und isolierte Testumgebungen für Unit- und Integrationstests zu schaffen.Der Hauptzweck von WireMock.NET ist es daher, einen HTTP-­Server-Mock anzubieten, der Anfragen auf der Basis voreingestellter Regeln empfängt und darauf reagiert. Es lässt sich genau definieren, wie auf eine spezifische HTTP-Anfrage, basierend auf URL, Methode, Headern oder Body-Inhalt, geantwortet werden soll. Dies ermöglicht ein hohes Maß an Flexibilität und Kontrolle über die Testumgebung.WireMock.NET [1] ist inspiriert von WireMock [2], einem populären Java-basierten Mocking-Tool, und wurde speziell für die .NET-Plattform entwickelt. Seit seiner Einführung hat es sich dank seiner einfachen Integration in bestehende
.NET-Projekte und seiner umfassenden Funktionalität schnell zu einem der führenden Tools in der .NET-Community entwickelt. Die Entwicklung von WireMock.NET ist von der Notwendigkeit angetrieben, eine robuste und flexible Lösung für das Mocking von HTTP-Services in der .NET-Umgebung zu bieten. Die Mitwirkenden rund um das Projekt sorgen für eine kontinuierliche Weiterentwicklung, um neue Features zu integrieren und sich an die sich ändernden Anforderungen der modernen Softwareentwicklung anzupassen.

Architektur auf Basis von Kernkomponenten

Die Architektur von WireMock.NET basiert auf einigen Kernkomponenten und ist speziell darauf ausgelegt, ein hohes Maß an Flexibilität und Kontrolle über das Verhalten von Mock-Services zu bieten. Dies ermöglicht eine effiziente Nachbildung externer APIs und Dienste für Testzwecke.
  • Server-Instanzierung: Im Herzen von WireMock.NET steht die Server-Instanz, die als zentraler Punkt für das Empfangen und Verarbeiten eingehender HTTP-Anfragen dient. Diese Instanz kann leicht konfiguriert und gestartet werden, wobei Entwickler spezifische Port-Nummern und andere Einstellungen wie SSL-Zertifikate und Proxy-Einstellungen festlegen können.
  • Request Matching: Ein Kernelement von WireMock.NET ist das ausgeklügelte Request-Matching-System. Es erlaubt Entwicklern, spezifische Regeln für das Erkennen eingehender Anfragen zu definieren, basierend auf URL-Pfaden, HTTP-Methoden, Headern, Query-Parametern und Body-Inhalten. Durch den Einsatz regulärer Ausdrücke oder benutzerdefinierter Matching-Implementierungen lassen sich komplexe Matching-Kriterien erstellen, um ein realistisches Mocking-Verhalten zu erreichen.
  • Response Definition: Nach dem erfolgreichen Matching einer Anfrage ermöglicht WireMock.NET die Definition einer maßgeschneiderten Antwort. Entwickler können den HTTP-­Statuscode, Header und Body der Antwort festlegen. Dank der Unterstützung für dynamische Antworten mittels Response Templating lassen sich Mock-Antworten basierend auf den Details der eingehenden Anfrage generieren, was eine noch genauere Simulation ermöglicht.
  • Erweiterte Funktionen: WireMock.NET bietet eine Vielzahl erweiterter Funktionen, die über einfaches Request Matching und Response Definition hinausgehen. Dazu gehören die Simulation von Netzwerkverzögerungen, das Erzeugen zufälliger Fehler, Stateful Behavior für das Simulieren von Anwendungen mit Zuständen und das Aufzeichnen und Wiedergeben von Anfragen für das Testen mit realen Daten. WireMock.NET bietet zudem die Möglichkeit, reale HTTP-Anfragen und -Antworten aufzuzeichnen und später als Mocks zu verwenden. Dies ist besonders nützlich, um realistische Testumgebungen zu schaffen.
  • Flexibilität und Erweiterbarkeit: Die Architektur von WireMock.NET ist so gestaltet, dass sie leicht erweitert und an spezifische Bedürfnisse angepasst werden kann. Entwickler können eigene Request Matcher und Response Transformer implementieren, um benutzerdefinierte Logik in den Mocking-Prozess einzubringen.

Installation und erste Server-Konfiguration

Die Installation von WireMock.NET in einem .NET-Projekt ist unkompliziert. Zunächst ist das WireMock.NET-Paket zu installieren – beispielsweise über den NuGet-Paketmanager, indem das folgende Kommando in der Entwicklungsumgebung oder über die Kommandozeile ausgeführt wird:

Install-<span class="hljs-keyword">Package</span> <span class="hljs-title">WireMock.Net</span> 
Nach der Installation ist die Bibliothek startklar, und wir können mit der Konfiguration des WireMock-Servers beginnen. Ein einfaches Beispiel in C# ist in Listing 1 zu sehen. In diesem Beispiel wird ein WireMock-Server auf Port 9091 erstellt, der auf GET-Anfragen an /example mit einer einfachen JSON-Antwort reagiert.
Listing 1: Die initiale Konfiguration eines WireMock-Servers
&lt;span class="hljs-keyword"&gt;using&lt;/span&gt; WireMock.&lt;span class="hljs-built_in"&gt;Server&lt;/span&gt;;&lt;br/&gt;&lt;span class="hljs-keyword"&gt;using&lt;/span&gt; WireMock.RequestBuilders;&lt;br/&gt;&lt;span class="hljs-keyword"&gt;using&lt;/span&gt; WireMock.ResponseBuilders;&lt;br/&gt;&lt;span class="hljs-keyword"&gt;using&lt;/span&gt; WireMock.Settings;&lt;br/&gt;&lt;span class="hljs-built_in"&gt;Console&lt;/span&gt;.WriteLine(&lt;span class="hljs-string"&gt;"WireMock.NET Demo Start"&lt;/span&gt;);&lt;br/&gt;var server = &lt;br/&gt;    WireMockServer.Start(&lt;span class="hljs-keyword"&gt;new&lt;/span&gt; WireMockServerSettings&lt;br/&gt;{&lt;br/&gt;  Port = &lt;span class="hljs-number"&gt;9091&lt;/span&gt;&lt;br/&gt;});&lt;br/&gt;server.Given(Request.Create().WithPath(&lt;span class="hljs-string"&gt;"/example"&lt;/span&gt;)&lt;br/&gt;  .UsingGet()).RespondWith(Response.Create()&lt;br/&gt;  .WithStatusCode(&lt;span class="hljs-number"&gt;200&lt;/span&gt;).WithBody(  &lt;br/&gt;    @&lt;span class="hljs-string"&gt;"{ "&lt;/span&gt;&lt;span class="hljs-string"&gt;"message"&lt;/span&gt;&lt;span class="hljs-string"&gt;": "&lt;/span&gt;&lt;span class="hljs-string"&gt;"Hello world!"&lt;/span&gt;&lt;span class="hljs-string"&gt;" }"&lt;/span&gt;));&lt;br/&gt;&lt;span class="hljs-built_in"&gt;Console&lt;/span&gt;.WriteLine($&lt;span class="hljs-string"&gt;"WireMock Server running at "&lt;/span&gt; +&lt;br/&gt;  &lt;span class="hljs-string"&gt;"{server.Urls[0]}"&lt;/span&gt;); 
Das Bild 1 verdeutlicht über Postman [3], dass diese paar Zeilen Code schon ausreichen, um einen Server zu definieren, der auf eine Anfrage eine vordefinierte Antwort liefert. Welche Konzepte und Funktionen dahinterstecken, beschreibt der gleichnamige Abschnitt weiter unten im Artikel.
Der Postman-Aufruf des ersten Demo-Mocks (Bild 1) © Autor
WireMock.NET hat Abhängigkeiten zu anderen .NET-Bi­bliotheken, die automatisch über NuGet verwaltet werden. Zu diesen gehören unter anderem Newtonsoft.Json für die JSON-Verarbeitung und Microsoft.AspNetCore.Http für die HTTP-Funktionalität. Die Installation der Bibliothek löst diese Abhängigkeiten automatisch auf und installiert sie mit.Die Bibliothek ist unter der MIT-Lizenz veröffentlicht und kann damit kostenlos in kommerziellen und nichtkommer­ziellen Projekten zum Einsatz kommen. Die sehr permissive MIT-Lizenz setzt wenig Einschränkungen hinsichtlich der Wiederverwendung des Codes. Die Bibliothek ist kompatibel mit verschiedenen .NET-Ver­sionen einschließlich .NET Core und .NET Framework. Dies macht sie vielseitig einsetzbar in unterschiedlichen Entwicklungsprojekten, unabhängig davon, ob es sich um Desktop-Anwendungen, Webdienste oder andere Arten von .NET-Anwendungen handelt.Der Hauptentwicklungsort für WireMock.NET ist GitHub. Das Repository enthält den Quellcode, Issue-Tracking und Dokumentation. WireMock.NET wurde ursprünglich von Stef Heyenrath entwickelt und wird nun von einer Gruppe von Mitwirkenden gepflegt. Bei Abfassung des Artikels ist Version 1.5.47 von Ende Januar 2024 aktuell.

Weitere Pakete

Neben der Kernbibliothek von WireMock.NET existieren noch zusätzliche Pakete und Erweiterungen, die die Funktio­nalität der Bibliothek erweitern oder die Integration in bestimmte Entwicklungsumgebungen und Testframeworks vereinfachen. Einige dieser zusätzlichen Pakete und Erweiterungen sind die folgenden:
  • WireMock.Net.StandAlone: Ein Paket, das es ermöglicht, Wire­Mock.NET als eigenständigen Mock-Server zu betreiben, ohne dass es in eine .NET-Anwendung eingebettet werden muss. Dies ist besonders nützlich für Szenarien, in denen Mock-Services unabhängig von der Hauptanwendung entwickelt, getestet oder bereitgestellt werden sollen.
  • WireMock.Net.AspNetCore: Eine Erweiterung für die Integration von WireMock.NET in ASP.NET-Core-Projekte. Dieses Paket erleichtert die Nutzung von WireMock.NET in der ASP.NET-Core-Umgebung, indem es spezifische Konfigurationsoptionen und Middleware-Komponenten bereitstellt, die für eine nahtlose Integration sorgen.
  • WireMock.Net.Client: Ein Client-Paket, das die Interaktion mit einem WireMock-Server über eine .NET-Anwendung ermöglicht. Dies kann nützlich sein, um WireMock-Server dynamisch zu konfigurieren oder Testdaten während der Laufzeit zu manipulieren.
  • WireMock.Net.Proxy: Ein Paket, das zusätzliche Funktionen für das Proxying von Anfragen durch den WireMock-Server bietet. Dies ist nützlich, um echte HTTP-Anfragen an ­einen Backend-Service weiterzuleiten und gleichzeitig bestimmte Anfragen mocken oder aufzeichnen zu können.
  • WireMock.Net.DependencyInjection: Ein Paket, das Unterstützung für die Dependency Injection von WireMock.NET in .NET-Projekte bietet. Dies erleichtert die Konfiguration und Verwaltung von WireMock-Servern in Projekten, die das Dependency-Injection-Modell verwenden.

Konzepte und Features

WireMock.NET bietet Softwareentwicklern eine breite Palette an Funktionen für das Erstellen und Verwalten von HTTP-Mocks. Die Grundlage von WireMock.NET bildet das Erstellen von Mocks für HTTP-Anfragen. Ein Mock in diesem Kontext ist eine vordefinierte Antwort, die der Server gibt, wenn eine bestimmte Anfrage gestellt wird. Die Erstellung eines Mocks erfolgt in zwei Schritten:
  • Definieren der Anfrage: Hier ist festgelegt, welche Anfragen von einem Mock-Server abgefangen werden sollen. Dies kann auf der Grundlage unterschiedlicher Kriterien erfolgen, zum Beispiel dem URL, der HTTP-Methode oder spezifischen Anfrage-Headern.
  • Spezifizieren der Antwort:Nachdem die Anfrage definiert ist, ist die Antwort des Mock-Servers zu bestimmen. Dies umfasst den HTTP-Statuscode, Antwort-Header und den Antwort-Body.
Das Request Matching ist ein zentraler Aspekt von WireMock.NET. Es ermöglicht die genaue Spezifikation, unter welchen Bedingungen eine Anfrage zu mocken ist. Folgende Methoden und Parameter lassen sich hierbei nutzen:
  • URL Matching: Dies ist die häufigste Form des Matchings. Es lassen sich exakte URLs oder Muster, beispielsweise mittels RegEx, definieren, um Anfragen zu matchen.
  • HTTP-Methoden: Mocks lassen sich für spezifische HTTP-Methoden wie etwa GET, POST, PUT, DELETE erstellen.
  • Header und Body-Inhalte: Auch das Matching auf Basis von Anfrage-Headern oder spezifischen Body-Inhalten ist möglich. Dies ist nützlich, um verschiedene Szenarien zu testen, die von diesen Parametern abhängen.
Nachdem eine Anfrage erfolgreich gematcht wurde, ist eine Definition notwendig, wie der Mock-Server antworten soll. Dazu gehören die nachfolgenden Möglichkeiten:
  • HTTP-Statuscodes:Jeder HTTP-Statuscode lässt sich als Antwort definieren, von 200 (OK) bis 500 (Internal Server Error), um verschiedene Szenarien zu simulieren.
  • Antwort-Header: Um das Verhalten des zu testenden Systems bei verschiedenen Arten von Antworten zu beurteilen, ist die Definition beliebiger Antwort-Header möglich.
  • Antwort-Body: Der Antwort-Body lässt sich festlegen, um bestimmte Daten zurückzugeben. Dies können einfacher Text, JSON, XML oder andere Inhaltsformate sein.
Neben den grundlegenden Mocking-Funktionen bietet Wire­Mock.NET auch erweiterte Funktionen, die es ermöglichen, noch realistischere Testszenarien zu erstellen. Dazu gehören die nachfolgenden Funktionen:
  • Delays: Durch die Definition von künstlichen Verzögerungen ist es möglich, das Verhalten eines Systems unter Bedingungen langsamer Netzwerkantworten zu testen.
  • Fehler-Simulation: Darüber hinaus ist es möglich, fehlerhafte Antworten zu simulieren, um zu sehen, wie eine Anwendung auf verschiedene Fehlerzustände, beispielsweise auf Netzwerkfehler oder Serverausfälle, reagiert.
  • Proxying: WireMock.NET lässt sich so konfigurieren, dass Anfragen an einen echten Server weitergeleitet und die Antworten zurück an den Client gesendet werden. Dies ist nützlich, um reale Antworten in Tests einzubeziehen und gleichzeitig bestimmte Anfragen zu mocken.
Um einige dieser Features von WireMock.NET besser zu verdeutlichen, zeigt das Listing 2 ein Beispiel. Darin ist ein Mock-Server erstellt, der auf GET-Anfragen an /wetter/heute mit einer JSON-Antwort reagiert, die Wetterinformationen enthält. Dies ermöglicht es, ein System unter vorhersagbaren und kontrollierten Bedingungen zu testen. Das Resultat einer Testabfrage mit Postman zeigt das Bild 2.
Listing 3: Das allgemeine Schema, um einen Mock-Server inklusive Request und Response zu erstellen
var &lt;span class="hljs-built_in"&gt;server&lt;/span&gt; = WireMockServer.Start(&lt;br/&gt;    &lt;span class="hljs-keyword"&gt;new&lt;/span&gt; WireMockServerSettings&lt;br/&gt;{&lt;br/&gt;  Port = &lt;span class="hljs-number"&gt;8080&lt;/span&gt;&lt;br/&gt;});&lt;br/&gt;&lt;span class="hljs-built_in"&gt;server&lt;/span&gt;.Given(&lt;span class="hljs-built_in"&gt;Request&lt;/span&gt;&lt;br/&gt;  .Create()...).RespondWith(&lt;span class="hljs-built_in"&gt;Response&lt;/span&gt;.Create()...); 
Der Aufruf der fiktiven Wetter-Route (Bild 2) © Autor

Weitere praktische Beispiele

Die Einrichtung eines einfachen Mock-Servers mit WireMock.NET hat die initiale Konfiguration bereits gezeigt. Neben einer Server-Instanz mit einem Port sind eine Request- und eine Response-Definition notwendig. Das Listing 3 verdeutlicht dieses Schema noch einmal.
Listing 2: Ein Mock-Server für eine API-Route
&lt;span class="hljs-built_in"&gt;server&lt;/span&gt;.Given(&lt;span class="hljs-built_in"&gt;Request&lt;/span&gt;.Create().WithPath(&lt;br/&gt;    &lt;span class="hljs-string"&gt;"/wetter/heute"&lt;/span&gt;).UsingGet())&lt;br/&gt;  .RespondWith(&lt;span class="hljs-built_in"&gt;Response&lt;/span&gt;.Create()&lt;br/&gt;    .WithStatusCode(&lt;span class="hljs-number"&gt;200&lt;/span&gt;)&lt;br/&gt;    .WithHeader(&lt;span class="hljs-string"&gt;"Content-Type"&lt;/span&gt;, &lt;span class="hljs-string"&gt;"application/json"&lt;/span&gt;)&lt;br/&gt;    .WithBody(@&lt;span class="hljs-string"&gt;"{ ""temperatur"": ""22°C"", &lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-string"&gt;      ""bedingungen"": ""sonnig"" }"&lt;/span&gt;)); 
Ein typisches Beispiel für eine solche Konfiguration ist der Test eines RESTful API. Angenommen, wir entwickeln eine Anwendung, die Daten von einem solchen REST-API abruft, dann zeigt das Beispiel in Listing 4, wie eine mögliche Anfrage inklusive Antwort konfiguriert werden kann. Im Beispiel ist ein Mock-Server konfiguriert, der auf GET-Anfragen an
/api/produkte mit einer JSON-Antwort reagiert, die eine Liste von Produkten enthält. Da diese Produkte im Code definiert sind, ist es problemlos möglich, diese ebenfalls zu randomisieren, um sehr unterschiedliche Daten zu testen. Eine andere Möglichkeit ist, diese Produktdaten aus vorgefertigten Ressourcen zu laden, um spezifische Testfälle nacheinander abzuarbeiten.
Listing 4: Ein gemockter API-Aufruf für fiktive Produkte
&lt;span class="hljs-built_in"&gt;server&lt;/span&gt;.Given(&lt;span class="hljs-built_in"&gt;Request&lt;/span&gt;.Create().WithPath(&lt;br/&gt;    &lt;span class="hljs-string"&gt;"/api/produkte"&lt;/span&gt;).UsingGet())&lt;br/&gt;  .RespondWith(&lt;span class="hljs-built_in"&gt;Response&lt;/span&gt;.Create()&lt;br/&gt;    .WithStatusCode(&lt;span class="hljs-number"&gt;200&lt;/span&gt;)&lt;br/&gt;    .WithHeader(&lt;span class="hljs-string"&gt;"Content-Type"&lt;/span&gt;, &lt;span class="hljs-string"&gt;"application/json"&lt;/span&gt;)&lt;br/&gt;    .WithBody(@&lt;span class="hljs-string"&gt;"[{ ""id"": 1, ""name"": &lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-string"&gt;      ""Produkt A"" }, { ""id"": 2, ""name"": &lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-string"&gt;      ""Produkt B"" }]"&lt;/span&gt;)); 
WireMock.NET ermöglicht es zudem, Fehlerzustände und Netzwerkausfälle zu simulieren. Dies ist besonders nützlich, um die Widerstandsfähigkeit einer Anwendung zu testen. Das Listing 5 zeigt dazu den Code, um einen HTTP-Code 500 auf eine Anfrage zurückzugeben. Das Ergebnis dieser Abfrage in Postman zeigt das Bild 3. In diesem Beispiel antwortet der Mock-Server auf Anfragen an /api/fehler mit einem 500-Serverfehler, was es ermöglicht, das Verhalten der Anwendung in diesem konkreten Fehlerfall zu testen.
Listing 6: Beispielhafte Einbindung von WireMock.NET in einen Unit-Test
&lt;span class="hljs-keyword"&gt;namespace&lt;/span&gt; &lt;span class="hljs-title"&gt;MeineApp.Tests&lt;/span&gt;&lt;br/&gt;{&lt;br/&gt;  [TestFixture]&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;public&lt;/span&gt; &lt;span class="hljs-keyword"&gt;class&lt;/span&gt; &lt;span class="hljs-title"&gt;MeineApiTests&lt;/span&gt;&lt;br/&gt;  {&lt;br/&gt;    &lt;span class="hljs-keyword"&gt;private&lt;/span&gt; WireMockServer _server;&lt;br/&gt;    [SetUp]&lt;br/&gt;    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;public&lt;/span&gt; &lt;span class="hljs-keyword"&gt;void&lt;/span&gt; &lt;span class="hljs-title"&gt;Setup&lt;/span&gt;(&lt;span class="hljs-params"&gt;&lt;/span&gt;)&lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-function"&gt;    &lt;/span&gt;{&lt;br/&gt;      server = WireMockServer.Start();&lt;br/&gt;      server.Given(Request.Create().WithPath(&lt;br/&gt;        &lt;span class="hljs-string"&gt;"/api/meinendpoint"&lt;/span&gt;).UsingGet())&lt;br/&gt;        .RespondWith(Response.Create()&lt;br/&gt;        .WithStatusCode(&lt;span class="hljs-number"&gt;200&lt;/span&gt;).WithBody(&lt;span class="hljs-string"&gt;"Testantwort"&lt;/span&gt;));&lt;br/&gt;    }&lt;br/&gt;    [Test]&lt;br/&gt;    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;public&lt;/span&gt; &lt;span class="hljs-keyword"&gt;void&lt;/span&gt; &lt;span class="hljs-title"&gt;ApiTest&lt;/span&gt;(&lt;span class="hljs-params"&gt;&lt;/span&gt;)&lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-function"&gt;    &lt;/span&gt;{&lt;br/&gt;      &lt;span class="hljs-comment"&gt;// Testcode using the mocked server...&lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-comment"&gt;    }&lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-comment"&gt;    [TearDown]&lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-comment"&gt;    public void TearDown()&lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-comment"&gt;    {&lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-comment"&gt;      server.Stop();&lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-comment"&gt;    }&lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-comment"&gt;  }&lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-comment"&gt;}&lt;/span&gt; 
Der Test einer absichtlich fehlerhaften API-Route in Postman (Bild 3) © Autor
WireMock.NET lässt sich nahtlos in bestehende .NET-Projekte integrieren. Listing 6 zeigt ein Beispiel eines NUnit-Testprojekts, in dem ein WireMock-Server für jeden Test initialisiert und nach dem Test wieder heruntergefahren wird. Der Server ist so konfiguriert, dass er auf bestimmte Anfragen während der Testausführung reagiert.
Listing 7: Ein Mock für eine API-Route inklusive Parameter
&lt;span class="hljs-built_in"&gt;server&lt;/span&gt;.Given(&lt;span class="hljs-built_in"&gt;Request&lt;/span&gt;.Create()&lt;br/&gt;    .WithPath(&lt;span class="hljs-string"&gt;"/api/kunde"&lt;/span&gt;).UsingGet()&lt;br/&gt;    .WithParam(&lt;span class="hljs-string"&gt;"id"&lt;/span&gt;, &lt;span class="hljs-keyword"&gt;new&lt;/span&gt; RegexMatcher(@&lt;span class="hljs-string"&gt;"\d+"&lt;/span&gt;)))&lt;br/&gt;  .RespondWith(&lt;span class="hljs-built_in"&gt;Response&lt;/span&gt;.Create()&lt;br/&gt;    .WithBody(&lt;span class="hljs-string"&gt;"{{request.query.id}}: Kunde gefunden"&lt;/span&gt;)&lt;br/&gt;    .WithTransformer()); 
Diese Beispiele verdeutlichen, wie WireMock.NET zum Einsatz kommen kann, um robuste und zuverlässige Tests für .NET-Anwendungen zu erstellen. Durch das Simulieren von externen Abhängigkeiten ermöglicht es WireMock.NET, verschiedene Szenarien zu testen, ohne auf echte externe Dienste oder APIs angewiesen zu sein. Dies erleichtert nicht nur das Testen, sondern steigert auch die Qualität insgesamt.

Erweiterte Funktionen und Techniken

WireMock.NET bietet eine Vielzahl von erweiterten Funktio­nen, die komplexere Testszenarien und eine genauere Steue­rung des Mock-Verhaltens ermöglichen. Diese fortgeschrittenen Techniken erlauben es, realistischere und dynamischere Mock-Umgebungen zu schaffen. Im Folgenden werden einige dieser Techniken mit C#-Beispielen vorgestellt.Response Templating ist eine leistungsfähige Funktion von WireMock.NET, die es ermöglicht, dynamische Antworten basierend auf der Anfrage zu generieren. Dies wird oft verwendet, um realistischere Mock-Services zu erstellen, die auf unterschiedliche Anfragen variabel reagieren können. Das Listing 7 zeigt dazu ein Beispiel. Das Ergebnis über Postman zeigt das Bild 4.
Listing 5: Beispiel für den Mock eines HTTP-500-Fehlers
&lt;span class="hljs-built_in"&gt;server&lt;/span&gt;.Given(&lt;span class="hljs-built_in"&gt;Request&lt;/span&gt;.Create().WithPath(&lt;br/&gt;    &lt;span class="hljs-string"&gt;"/api/fehler"&lt;/span&gt;).UsingGet())&lt;br/&gt;  .RespondWith(&lt;span class="hljs-built_in"&gt;Response&lt;/span&gt;.Create().WithStatusCode(&lt;span class="hljs-number"&gt;500&lt;/span&gt;)&lt;br/&gt;  .WithBody(&lt;span class="hljs-string"&gt;"Interner Serverfehler"&lt;/span&gt;)); 
Der Aufruf der dynamischen API-Route mit Postman (Bild 4) © Autor
In diesem Beispiel wird ein Mock-Server eingerichtet, der auf GET-Anfragen an /api/kunde reagiert und den Wert des id-Parameters in der Antwort zurückgibt. Wenn also eine Anfrage mit /api/kunde?id=1234 gesendet wird, antwortet der Server mit „1234 Kunde gefunden“. Wird keine Zahl übergeben, schlägt der RegEx-Mapper nicht an und es erscheint die Fehlermeldung:

{
  “Status”: “No matching mapping found”
} 
Stateful Behavior ermöglicht es, das Verhalten des Mock-Servers auf der Grundlage des aktuellen Zustands zu ändern. Das ist besonders dann nützlich, wenn komplexere Interak­tionen simuliert werden sollen, wie sie in echten Anwendungen häufig vorkommen. Ein Beispiel dazu zeigt das Listing 8. Hier wird ein Szenario erstellt, in dem der Server seinen Zustand basierend auf den eingehenden Anfragen ändert. Anfangs antwortet der Server mit „Nicht angemeldet“, wechselt dann aber in den Zustand „Angemeldet“ und antwortet entsprechend.
Listing 8: Zwei Mocks für die Simulation eines Statuswechsels
&lt;span class="hljs-selector-tag"&gt;server&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.Given&lt;/span&gt;(Request.Create().WithPath(&lt;span class="hljs-string"&gt;"/api/status"&lt;/span&gt;)&lt;br/&gt;    .UsingGet())&lt;br/&gt;  &lt;span class="hljs-selector-class"&gt;.InScenario&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Statuswechsel"&lt;/span&gt;)&lt;br/&gt;  &lt;span class="hljs-selector-class"&gt;.WillSetStateTo&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Angemeldet"&lt;/span&gt;)&lt;br/&gt;  &lt;span class="hljs-selector-class"&gt;.RespondWith&lt;/span&gt;(Response.Create().WithBody(&lt;br/&gt;    &lt;span class="hljs-string"&gt;"Nicht angemeldet"&lt;/span&gt;));&lt;br/&gt;&lt;span class="hljs-selector-tag"&gt;server&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.Given&lt;/span&gt;(Request.Create().WithPath(&lt;span class="hljs-string"&gt;"/api/status"&lt;/span&gt;)&lt;br/&gt;    .UsingGet())&lt;br/&gt;  &lt;span class="hljs-selector-class"&gt;.InScenario&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Statuswechsel"&lt;/span&gt;)&lt;br/&gt;  &lt;span class="hljs-selector-class"&gt;.WhenStateIs&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Angemeldet"&lt;/span&gt;)&lt;br/&gt;  &lt;span class="hljs-selector-class"&gt;.RespondWith&lt;/span&gt;(Response.Create().WithBody(&lt;br/&gt;     &lt;span class="hljs-string"&gt;"Angemeldet"&lt;/span&gt;)); 
Die Record-und-Playback-Funktion von WireMock.NET ist nützlich, um reale API-Antworten aufzuzeichnen und diese später in Tests zu verwenden. Dies ist besonders hilfreich, wenn komplexe APIs im Einsatz sind, deren Verhaltensweisen schwierig manuell zu mocken sind. Das Snippet in Listing 9 zeigt, wie eine Aufzeichnung gestartet und gestoppt wird. Die aufgezeichneten Daten lassen sich anschließend für zukünftige Tests wiederverwenden.
Listing 9: Beispiel für das Aufzeichnen von API-Aufrufen für die spätere Nutzung
var server = WireMockServer.Start();&lt;br/&gt;server.StartRecording(&lt;span class="hljs-string"&gt;"http://echte-api.com"&lt;/span&gt;);&lt;br/&gt;&lt;span class="hljs-regexp"&gt;//&lt;/span&gt; Ausführen von realen Anfragen an das echte API&lt;br/&gt;&lt;span class="hljs-regexp"&gt;//&lt;/span&gt; ...&lt;br/&gt;&lt;span class="hljs-regexp"&gt;//&lt;/span&gt; Stoppen des Recordings und Speichern der Anfragen&lt;span class="hljs-regexp"&gt;/&lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-regexp"&gt;/&lt;/span&gt;&lt;span class="hljs-regexp"&gt;/ Antworten&lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-regexp"&gt;server.StopRecording();&lt;/span&gt; 
Diese fortgeschrittenen Funktionen von WireMock.NET erweitern die Möglichkeiten für das Testen von Software erheblich. Durch die Verwendung dynamischer Antwortvorlagen, zustandsabhängiger Mocks und der Fähigkeit, echte API-Antworten aufzuzeichnen und wiederzuverwenden, lassen sich realistischere und anspruchsvollere Testumgebungen schaffen.

Integrationstests mit WireMock.NET

Integrationstests spielen eine entscheidende Rolle in der Softwareentwicklung. Sie überprüften die korrekte Interaktion zwischen verschiedenen Modulen und externen Diensten ­einer Anwendung. WireMock.NET bietet eine effiziente ­Lösung, um externe HTTP/HTTPS-Dienste zu mocken, was eine isolierte und kontrollierbare Testumgebung für Integra­tionstests ermöglicht. Durch die Simulation externer Abhängigkeiten mit WireMock.NET lässt sich sicherstellen, dass die Integrationstests konsistent und unabhängig von externen Faktoren durchgeführt werden.WireMock.NET ermöglicht es, externe Services zu isolieren, indem es deren Verhalten in einer Testumgebung nachbildet. Dies reduziert die Variabilität in Tests und verbessert die Reproduzierbarkeit der Ergebnisse. Externe Abhängigkeiten sind nicht immer zugänglich oder stabil. Durch das Mocking dieser Dienste mit WireMock.NET lassen sich Tests jederzeit durchführen, ohne auf externe Services angewiesen zu sein. Das Beispiel aus Listing 10 zeigt die Kombination von WireMock.NET und xUnit.
Listing 10: Ein Integrationstest mit xUnit
public class WetterServiceTest&lt;br/&gt;{&lt;br/&gt;  [Fact]&lt;br/&gt;  public void WetterService_RuftDatenAb_KeinFehler()&lt;br/&gt;  {&lt;br/&gt;    &lt;span class="hljs-regexp"&gt;//&lt;/span&gt; Einrichten des WireMock-Servers&lt;br/&gt;    var server = WireMockServer.Start();&lt;br/&gt;    server.Given(Request.Create().WithPath(&lt;br/&gt;        &lt;span class="hljs-string"&gt;"/wetter/today"&lt;/span&gt;).UsingGet())&lt;br/&gt;      .RespondWith(Response.Create()&lt;br/&gt;        .WithStatusCode(&lt;span class="hljs-number"&gt;200&lt;/span&gt;)&lt;br/&gt;        .WithBody(@&lt;span class="hljs-string"&gt;"{"&lt;/span&gt;&lt;span class="hljs-string"&gt;"temperatur"&lt;/span&gt;&lt;span class="hljs-string"&gt;": "&lt;/span&gt;&lt;span class="hljs-string"&gt;"22°C"&lt;/span&gt;&lt;span class="hljs-string"&gt;"}"&lt;/span&gt;));&lt;br/&gt;    &lt;span class="hljs-regexp"&gt;//&lt;/span&gt; Konfigurieren der Anwendung, um den &lt;br/&gt;    &lt;span class="hljs-regexp"&gt;//&lt;/span&gt; Mock-Server zu verwenden&lt;br/&gt;    var wetterService = new WetterService(&lt;br/&gt;      server.Urls[&lt;span class="hljs-number"&gt;0&lt;/span&gt;] + &lt;span class="hljs-string"&gt;"/wetter/today"&lt;/span&gt;);&lt;br/&gt;    &lt;span class="hljs-regexp"&gt;//&lt;/span&gt; Ausführen der Methode, die getestet werden &lt;br/&gt;    &lt;span class="hljs-regexp"&gt;//&lt;/span&gt; soll&lt;br/&gt;    var wetter = wetterService.RufeWetterdatenAb();&lt;br/&gt;    &lt;span class="hljs-regexp"&gt;//&lt;/span&gt; Überprüfen, ob die Methode wie erwartet &lt;br/&gt;    &lt;span class="hljs-regexp"&gt;//&lt;/span&gt; funktioniert&lt;br/&gt;    Assert.Equal(&lt;span class="hljs-string"&gt;"22°C"&lt;/span&gt;, wetter.Temperatur);&lt;br/&gt;    &lt;span class="hljs-regexp"&gt;//&lt;/span&gt; Aufräumen&lt;br/&gt;    server.Stop();&lt;br/&gt;  }&lt;br/&gt;} 

Best Practices und Tipps

Die effektive Nutzung von WireMock.NET in Testumgebungen, Performance-Optimierung und das Management von Ressourcen sowie die Berücksichtigung von Sicherheitsaspekten sind essenziell, um die Vorteile dieses Tools vollständig auszuschöpfen. Im Folgenden werden einige Best Practices und hilfreiche Tipps für den Umgang mit WireMock.NET dargelegt.WireMock.NET sollte zum Einsatz kommen, um isolierte Testumgebungen zu schaffen, die externe Abhängigkeiten simulieren. Dies gewährleistet, dass Tests konsistent und reproduzierbar sind, unabhängig von der Verfügbarkeit oder dem Zustand externer Services. Auch wenn WireMock.NET darauf ausgelegt ist, effizient zu sein, ist die Ressourcennutzung, wie zum Beispiel Speicher und die CPU-Auslastung, im Blick zu behalten, besonders wenn eine große Anzahl von Mocks oder komplexe Simulationen zum Einsatz kommen.Zudem sollten wir es vermeiden, unnötig große Datenmengen in Mock-Antworten zu verwenden, da dies die Testperformance beeinträchtigen kann. Stattdessen sind repräsentative Daten zu bevorzugen, die für die Testfälle relevant sind. Wenn möglich, ist auf die parallele Ausführung von Tests zu achten, um die Testlaufzeiten zu verkürzen. Wir müssen aber sicherstellen, dass dies nicht zu Konflikten innerhalb der simulierten Umgebungen führt.

Vergleich mit anderen Projekten

Neben WireMock.NET existieren andere Projekte und Bibliotheken, die ähnliche Funktionalitäten bieten und in bestimmten Szenarien als Alternativen oder Ergänzungen zu WireMock.NET eingesetzt werden können:
  • MockServer [4] ist ein vielseitiges Tool, das nicht nur für .NET, sondern auch für andere Programmiersprachen wie Java und Node.js verfügbar ist. Es ermöglicht das Mocking von HTTP- und HTTPS-Anfragen sowie das Erstellen von Erwartungen, die in einer Vielzahl von Testszenarien verwendet werden können. MockServer unterstützt auch die Aufzeichnung und Wiedergabe von Anfragen, was die Erstellung von Mocks aus realen Daten erleichtert.
  • Mountebank [5] bietet sprachunabhängige Mocking-Funktionalitäten, die eine breite Palette von Entwicklungsumgebungen unterstützen. Es ist bekannt für seine Fähigkeit, auch Nicht-HTTP-Protokolle wie TCP und SMTP zu mocken, was es zu einer vielseitigen Wahl für komplexe Testumgebungen macht. Mountebank betont die Bedeutung von Testisolation und ermöglicht es Entwicklern, Dienste zu simulieren, ohne externe Abhängigkeiten einzubinden.
  • Postman [3], ein weit verbreitetes Tool für die Entwicklung und das Testen von APIs, ermöglicht es auch, Mock-Server zu erstellen. Obwohl Postman hauptsächlich als API-Entwicklungsumgebung bekannt ist, ermöglichen seine Mock-Server-Funktionen das Simulieren von API-Antworten, was die Entwicklung und das Testen von Front­end-Anwen­dun­gen erleichtert, die auf diese APIs angewiesen sind.
  • Pact [6] ist ein Framework, das sich auf das Testen von API-Integrationen konzentriert, indem es Verträge zwischen Servicekonsumenten und -anbietern erstellt und validiert. Pact unterstützt mehrere Programmiersprachen und Plattformen und ermöglicht es sicherzustellen, dass APIs wie erwartet funktionieren, basierend auf den definierten Verträgen. Pact ist besonders nützlich in Microservices-Architekturen, wo die Interaktionen zwischen Diensten genau definiert und getestet werden müssen.
  • NSubstitute [7] for http ist eine spezialisierte Bibliothek für .NET, die das Mocking von HTTP-Anfragen für Tests vereinfacht. Es arbeitet nahtlos mit HttpClient zusammen und bietet eine einfache Syntax für das Definieren von Mock-Antworten. NSubstitute for http eignet sich ideal für Entwickler, die bereits NSubstitute in ihren Projekten verwenden und eine konsistente Mocking-Erfahrung für HTTP-Anfragen wünschen.
Während WireMock.NET speziell für die .NET-Plattform entwickelt wurde und eine umfangreiche Unterstützung für das Mocking von HTTP/HTTPS-Diensten bietet, bieten die vorgestellten Alternativen unterschiedliche Perspektiven und Funktionalitäten, die in bestimmten Projektkontexten vorteilhaft sein können. Tools wie MockServer und Mountebank bieten eine breitere Sprachunterstützung und zusätzliche Protokollfunktionen, während Postman und Pact einen stärkeren Fokus auf API-Entwicklung und -Integration legen. NSubstitute for http bietet eine enge Integration in das .NET-Ökosystem, insbesondere für Projekte, die bereits NSubsti­tute verwenden.

Fazit

Durch seine umfassenden Möglichkeiten zum Mocking und Simulieren von HTTP/HTTPS-Services etabliert sich WireMock.NET als unverzichtbares Instrument in der .NET-Community. Dieses Tool erlaubt es, komplexe Mocking-Szenarien effektiv zu realisieren und präzise auf Testanforderungen zuzuschneiden. Die flexible und erweiterbare Konzeption von WireMock.NET unterstützt die Erstellung realistischer Testumgebungen durch präzises Request Matching und die Generierung dynamischer Antworten.Die Vielseitigkeit von WireMock.NET zeigt sich in der breiten Palette seiner Anwendungsmöglichkeiten. Von der Einrichtung einfacher Mock-Server bis hin zu fortgeschrittenen Szenarien wie der Simulation von Netzwerkausfällen und der Implementierung zustandsabhängiger Mocks deckt WireMock.NET eine Vielzahl von Einsatzmöglichkeiten ab. Diese Anwendungen demonstrieren, wie WireMock.NET in unterschiedlichen Phasen der Softwareentwicklung und bei diversen Teststrategien eingesetzt werden kann, um die Qualität und Zuverlässigkeit von Softwareprodukten zu steigern.Die Einordnung von WireMock.NET im Vergleich zu anderen verfügbaren Mocking-Tools verdeutlicht zudem, dass seine spezielle Ausrichtung auf die .NET-Plattform und die umfangreichen Mocking-Fähigkeiten es zu einer ausgezeichneten Wahl für .NET-Entwickler machen.WireMock.NET ist daher nicht nur ein Werkzeug, sondern ein integraler Bestandteil des Testökosystems, der entscheidend zur Entwicklung robuster und fehlerresistenter Anwendungen beiträgt. Die Bibliothek lässt sich schnell in eigene Projekte integrieren, die Dokumentation ist gut, und die Implementierung von Testfällen gestaltet sich unkompliziert. Insgesamt bietet WireMock.NET einen lohnenden Einstieg in die Welt des Mockings und verdient sich durch den einfachen Einsatz und die zahlreichen Funktionen ein „Sehr gut“ und eine klare Empfehlung.

Fussnoten

  1. Das GitHub-Repository zu WireMock.NET, http://www.dotnetpro.de/SL2404Frameworks1
  2. Die Projektseite zu WireMock, https://wiremock.org
  3. Die Website zu Postman, http://www.postman.com
  4. Die Website zum Projekt MockServer, http://www.mock-server.com
  5. Die Projektseite zu Mountebank, http://www.mbtest.org
  6. Die Website zum Framework Pact, https://pact.io
  7. Das Repository zu NSubstitute auf GitHub, http://www.dotnetpro.de/SL2404Frameworks2

Neueste Beiträge

DWX hakt nach: Wie stellt man Daten besonders lesbar dar?
Dass das Design von Websites maßgeblich für die Lesbarkeit der Inhalte verantwortlich ist, ist klar. Das gleiche gilt aber auch für die Aufbereitung von Daten für Berichte. Worauf besonders zu achten ist, erklären Dr. Ina Humpert und Dr. Julia Norget.
3 Minuten
27. Jun 2025
DWX hakt nach: Wie gestaltet man intuitive User Experiences?
DWX hakt nach: Wie gestaltet man intuitive User Experiences? Intuitive Bedienbarkeit klingt gut – doch wie gelingt sie in der Praxis? UX-Expertin Vicky Pirker verrät auf der Developer Week, worauf es wirklich ankommt. Hier gibt sie vorab einen Einblick in ihre Session.
4 Minuten
27. Jun 2025
„Sieh die KI als Juniorentwickler“
CTO Christian Weyer fühlt sich jung wie schon lange nicht mehr. Woran das liegt und warum er keine Angst um seinen Job hat, erzählt er im dotnetpro-Interview.
15 Minuten
27. Jun 2025
Miscellaneous

Das könnte Dich auch interessieren

UIs für Linux - Bedienoberflächen entwickeln mithilfe von C#, .NET und Avalonia
Es gibt viele UI-Frameworks für .NET, doch nur sehr wenige davon unterstützen Linux. Avalonia schafft als etabliertes Open-Source-Projekt Abhilfe.
16 Minuten
16. Jun 2025
Mythos Motivation - Teamentwicklung
Entwickler bringen Arbeitsfreude und Engagement meist schon von Haus aus mit. Diesen inneren Antrieb zu erhalten sollte für Führungskräfte im Fokus stehen.
13 Minuten
19. Jan 2017
Evolutionäres Prototyping von Business-Apps - Low Code/No Code und KI mit Power Apps
Microsoft baut Power Apps zunehmend mit Features aus, um die Low-Code-/No-Code-Welt mit der KI und der professionellen Programmierung zu verbinden.
19 Minuten
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige