Mocks in der Testumgebung (Teil 3)

Im zweiten Teil haben wir gesehen, wie man mit Hilfe eines Mock-Framework (in diesem Fall Moq) eine Anwendung so anpassen kann, dass bestimmte Schnittstellen für Tests gemockt werden und somit keine Fehler liefern können.

In diesem Teil erstellen wir eine selbst programmierte Mock-Anwendung und werden mit unserer Heldendatenbank darauf zugreifen. Hierzu verwenden wir „Docker for Windows“, welches seit Windows 10 genutzt werden kann. Vor Windows 10 musste man Hyper-V verwenden, um z. B. eine Linux-Maschine zu simulieren, auf der man Container über Docker laufen lassen konnte. Mit dem neusten Betriebssystem von Microsoft ist dieses Vorgehen auch auf Windows möglich. Man kann sich die neuste Version auf Docs.docker.com herunterladen und installieren. Der dafür heruntergeladene Installer bereitet das System für Docker vor.

Mit Docker starten wir unsere Heldendatenbank – genauso wie die gleich neu erstellte APImock-Anwendung. Mit dem Postman werden wir daraufhin eine POST-Anfrage durchführen, die über die Heldendatenbank in den APImock läuft.

Abbildung 1: Darstellung der Applikation

Visual Studio verfügt über eine Extension, die die Unterstützung mit Docker erlaubt. Beim Erstellen eines neuen Projektes können wir im Fenster für die Vorlagen ein Häkchen setzen, um das Projekt mit Docker für Windows zu kombinieren. Außerdem verwenden wir die Web-API-Vorlage um kein komplett neues Projekt erstellen zu müssen.

Erstellung einer Web-API in Visual Studio
Abbildung 2: Erstellung einer Web-API in Visual Studio

Beim Laden des Projekts wird direkt ein Image im Docker erstellt. Bei jedem neuen Build des Projekts wird das Image in Docker aktualisiert.

Wir können nun zeitgleich mit der PowerShell von Windows die Docker-Befehle ausführen, um unsere aktuellen Images auszulesen.

Von Visual Studio erstellte Images
Abbildung 3: Von Visual Studio erstellte Images

Die Images können, ähnlich wie bei GitHub, in ein Repository für Versionskontrollen und für den Zugriff von verschiedenen Arbeitsplätzen hochgeladen werden. Dafür muss der Tag des Images an den Repository-Namen angepasst und mit dem Push-Befehl darauf hochgeladen werden.

Upload ins Docker Repository
Abbildung 4: Upload ins Docker Repository

Da die Web-API-Vorlage genutzt wurde, sind in der Controller-Klasse bereits die vier Standard-Rest-Befehle (GET, POST, DELETE, PUT) vorgeneriert. Wir löschen alle Funktionen bis auf POST, da es sich hierbei für den Mock um eine „banale Funktion“ handeln soll.

Ausschnitt Code - API-Route der Funktion
Abbildung 5: Codeausschnitt – API-Route der Funktion

Somit haben wir nun eine Anwendung, die nur eine Funktion hat und nichts anderes ausführt. Der Grundgedanke für diese Schnittstelle ist, dass die Datenbank-API den Heldennamen an diese Anwendung schickt, um die Items-Konfiguration für den jeweiligen Helden zu bekommen. Dabei wird die PostMock()-Funktion bei einer POST-Anfrage ausgeführt und der mitgelieferte Heldenname würde für die Anfrage den Algorithmus verwenden. Hier wird allerdings statt eines Algorithmus ein fester String eingesetzt, welcher immer dieselbe Antwort auf jede Anfrage liefert. Somit ist sichergestellt, dass keine Fehler von der neuen Anwendung kommen. So kann auch sichergestellt werden, dass diese Schnittstelle wie gewünscht funktioniert.

Ausschnitt Code: POST-Zugriff auf die API
Abbildung 6: Codeausschnitt: POST-Zugriff auf die API

In der Heldendatenbank-API wurde eine POST-Funktion implementiert, die die Anfrage auf den Heldennamen an die APImock weiterleitet. Dafür wird die WebClient-Klasse verwendet, welche mit einem String (Heldenname) gefüllt wird. Diese wird dann über die Funktion der Klasse UploadValues() weitergeleitet.

Beide Anwendungen sind nun fertig und können im Visual Studio über den Docker-Button gestartet werden. Sobald beide Anwendungen gestartet wurden, kann man sich über die PowerShell die aktuell laufenden Container anschauen. Mit dem Docker-Befehl „docker ps“ erfahren wir auch den Port, auf den die Container laufen.

Ausschnitt aktuell laufende Container
Abbildung 7: Aktuell laufende Container

Wenn wir nun mit dem Postman eine Anfrage auf die Route „api/Helden/MockItems“ der Heldendatenbank-API ausführen, wird diese an den APImock weitergeleitet und wir sehen die Antwort für den Helden „Maria“.

Ausschnitt Schnittstellentest mit Postman
Abbildung 8: Schnittstellentest mit Postman

Die nicht gemockte Anwendung würde in diesem Fall für den Helden „Maria“ die passenden Ausrüstungsgegenstände auflisten. Da es sich hier allerdings um einen Mock handelt, ist der Rückgabe-String „Schwert“ passend zur festen Variable, die wir gesetzt haben.

Somit können nun sämtliche Funktionen getestet werden, welche die Schnittstelle zur APImock nutzen, ohne Fehler von der APImock zu erwarten.

Nun haben wir drei verschiedene Varianten gesehen, wie Mocks eingesetzt werden können:

  1. Das Framework-Moq, welches dafür genutzt wird, Mock-Objekte innerhalb der Anwendung zu erstellen
  2. API-Tools (Postman), die eine Art Mock für das Frontend darstellen
  3. Eine Selbstgeschriebene Anwendung, die als Mock dient

Ich hoffe, ich konnte Ihnen hiermit einen kleinen Einblick in der Welt der Mocks geben.

Mocks in der Testumgebung (Teil 2)

Im ersten Teil wurden Grundlagen zum Mock und das Beispielprojekt vorgestellt. Im zweiten Teil bauen wir einen Mock auf, der unsere Rest-Service-Anwendung interaktiv testet.

Nun kommt es zu der Frage: „Warum sollte ich bei diesem Beispiel einen Mock verwenden?“ Es ist immerhin eine einfache, übersichtliche Anwendung. Wir müssen allerdings beachten, dass wir die Standardfunktionalität der API testen wollen. Wenn wir einen GET- oder POST-Befehl durchführen, wird innerhalb des Rest-Services der komplette Weg zur Datenbank genommen, um auf die Daten, die bereits gespeichert sind, zuzugreifen. An diesem Punkt kommt der Mock ins Spiel. Es wird der Zugriff auf die Datenbank, mit Hilfe des Mocks simuliert. Somit kann sichergestellt werden, dass falls ein Fehler gefunden wird, dieser nichts mit dem Zugriff auf die Datenbank zu tun hat, sondern mit dem Bereich in dem wir den Test durchgeführt haben. Das wäre ein Beispiel für das Anwendungsgebiet. Ein weiteres wäre der Zugriff von außen auf die API. Im Normalfall würde eine solche API ein Frontend zur Eingabe der Informationen besitzen. Da wir allerdings die Pfade kennen, in die die Daten eingespeist werden, können wir ein API-Tool verwenden, welches das Frontend simuliert und spezifische Daten an die API schickt.

Ich werde in diesem Teil auf das Mock-Framework „Moq“ eingehen und das API-Test-Tool „Postman“.

Moq ist ein kleines und einfaches Mock-Framework für .Net oder C#. Es gibt mehrere Framework (NSubstitute, Rhino Mocks, etc …) doch diese sind meist recht kompliziert zu verwenden. Moq sticht in dem Sinne heraus, dass es eine einfache Syntax verwendet und für die meisten Anwendungsgebiete vollkommend ausreichend ist. Das Moq Framework-Package kann über Visual Studio einfach mit dem Nuget-Tool heruntergeladen und direkt in dem Quellcode eingebunden werden.

using System.Net.Http;
using Moq;
using NUnit.Framework;

Hier der einfache Aufbau eines Unit-Tests. Wir erstellen eine neue Heldenliste, welche ihre Daten aus der Datenbank bekommt. Mit diesen Informationen können wir den Service erstellen, der von der API abgerufen wird. Wir rufen den vierten Helden auf, den wir eingespeichert haben. In diesem Fall wäre es „Maria“.

[Test]
  public void TestMethodwithoutMoq()
{
     //Arrange (Create)
   Heldenliste liste = new Heldenliste();
   var heldAPI = new HeldenService(liste);
   string shouldBe = "Maria";
   //Act (Test)
   var ergebnis = heldAPI.GetHeroName(4);
   //Assert (Verify)
   Assert.That(ergebnis,Is.EqualTo(shouldBe),"Is Not as Aspected");
   }
[Route("api/Helden/{number}")]
[HttpGet]
public string GetHeroName(int number)
{
   Held hero = heldenAPI.GetHero(number)
   Return hero.name;
}

Jetzt nehmen wir den bereits vorhandenen Aufbau und ersetzen die Heldenliste mit einem Mock. Somit verwenden wir nicht mehr die Daten, die in der Datenbank gespeichert sind und haben die Anwendung erstmal von der Datenbank getrennt. Mit diesem Aufbau ist garantiert, dass keine Fehler von der Datenbankverbindung den Test behindern.

[Test]
public void TestMethodwithMoq()
{
    Helden mockHero = new Helden()
{
    Name = "Detlef",
    Klasse = "Zauberer",
    Alter = 40,
    Level = 14
};
//Arrange (Create)
var moqHeldenliste = new Mock();
moqHeldenliste.Setup(x => x.GetHero(It.IsAny()))
    .Returns(() => mockHero);
var heldenapi_mock = new HeldenAPI(moqHeldenliste.Object);
var shouldBe = "Detlef";
//Act (Test)
var ergebnis = heldenapi_mock.GetHeroName(It.IsAny());
//Assert (Verify)
Assert.That(ergebnis, Is.EqualTo(shouldBe), "Is Not as Aspectet");
}

Wenn das Moq-Framework integriert ist, kann man die Klasse-„Mock“ verwenden. Bei der Verwendung der Klasse gibt man an welche Klasse simuliert werden soll. Der nächste Schritt ist es dann den Mock mit der Setup()-Funktion zu konfigurieren. Wir geben an, dass egal nach welchem Helden gefragt wird(It.IsAny), immer der mockHero(Detlef) ausgegeben wird. Würden wir den Mock nicht konfigurieren, würde er bei dem Aufruf der GetHeroName()-Funktion einen Default-Wert als Integer nehmen. Bei diesem handelt es sich meist um „0“. Da allerdings keine Daten aus der Datenbank geholt werden, würde er einen Fehler zurückgeben.

Das Moq-Framework lässt sich gut nutzen, um die Funktionalitäten die die API innerhalb ihrer Anwendung aufruft zu testen. Bei dem direkten Aufruf der API kommt sie allerdings an ihre Grenzen. Hier kommt das API-Tool „Postman“ ins Spiel.

„Postman“ kann man als separate Anwendung installieren oder als Chrome-Plugin verwenden. Er ist ausgerüstet mit den meisten REST-Befehlen (GET, POST, PUT, etc…) und weist eine leicht bedienbare Oberfläche auf. Es ist möglich, Testfälle zu schreiben, die während der REST-Befehle ablaufen und mit den gesendeten oder empfangenen Daten arbeiten. Somit bauen wir mit ihm einen Mock, der das Frontend simuliert.

API-Test-Tool „Postman“

Es können „Collections“ erstellt werden, in denen man die REST-Befehle, die wir im letzten Teil verwendet haben, gespeichert werden können. Mit dem POST-Befehl haben wir die Heldin Maria über die API gespeichert. Jetzt wurde noch ein Testfall hinzugefügt, welcher den Antworttext überprüft, den wir von der API zurückbekommen haben. In einem positiven Fall wird zurückgemeldet, dass der gewünschte Held hinzugefügt wurde. In einem Negativ-Fall würden wir eine andere Meldung bekommen und der Testfall würde Failed zurückgeben.

API-Test-Tool „Postman“

Unserer „Collection“ fügen wir auch die Abfrage nach dem letzten zugefügten Helden hinzu. Es können noch viele weitere Abfragen mit eigenen Testfällen der „Collection“ hinzugefügt werden, doch für unser Beispiel reichen diese beiden. Nun ist es möglich die komplette „Collection“ zu starten. Der „Postman“ wird darauf hin nacheinander alle REST-Befehle aufrufen und ihre dazu gespeicherten Testfälle durchgehen. Somit bekommen wir am Ende solch ein Ergebnis:

API-Test-Tool „Postman“

Somit sehen wir, dass der Zugriff von außerhalb, auf die API funktioniert.
Mit diesen Beispielen sehen wir, dass mit dem Moq Framework die Anwendung hinter der API einfach getestet werden kann. Der „Postman“ hingegen vereinfacht, dass testen der API von Seiten des Internets.

Überblick Postman und Moq Framework

Im nächsten Teil werden wir uns weiterhin mit diesem Thema befassen. Dabei werden wir in Docker eine kleine Testumgebung aufbauen, in dem der Rest-Service mit der Datenbank aufgebaut wird, und eine selbst geschriebene Mock Anwendung wird kontinuierlich Zugriff auf die Rest API versuchen. Diese Variante könnte man im späteren Verlauf auch als Lasttest verwenden.

Das was Mocks in der Testumgebung Teil 2 und hier geht es zu Teil 3.