Mock Server betreiben mit Mountebank und Docker

Keine Kommentare

Bei der Entwicklung von Applikationen die von anderen Systemen abhängig sind, z.B. durch die Anbindung von Geschäftslogik und Daten, steht man vor der Frage, wie diese getestet werden sollen, falls die Systeme nicht verfügbar sind. Klassischerweise würde diese Anbindung über Mocks in Unit- oder funktionalen Tests durchgeführt werden. Trotzdem kann auf dem Weg durch die Applikation bis zur Netzwerkschicht einiges schief gehen.

In diesem Artikel betrachten wir eine Lösung, die einen Mock Server für solche allumfassenden Tests bereitstellt. Auf diese Art können Aufrufe durch eine Applikation gegen einen Mock Server durchgeführt und tiefgreifend getestet werden. Dadurch werden allumfassende Applikation und System-Ende-zu-Ende-Tests ermöglicht.

Mountebank

Mountebank ist ein Open Source Tool, das plattformunabhängige Multi-Protokoll Test Doubletten auf der Netzwerkschicht bereitstellt [1]. Eine zu testende Applikation muss nur auf die IP oder URL der Mountebank Instanz verweisen, statt auf die reale Abhängigkeit. Das ermöglicht, die Applikation durch alle Applikationsschichten zu testen, wie man es sonst traditionell mit Stubs und Mocks tun würde. Unterstützte Protkolle sind HTTP, HTTPS, TCP und SMTP.

Zu diesem Zweck steht eine DSL bereit, die genutzt werden kann, um Imposter Stubs zu konfigurieren, welche statisch oder dynamisch Responses für Requests erstellen [2]. Diese Stub-Funktionalität ist mit einem Proxy Mode erweiterbar, der Aufrufe zu den Originalsystemen aufnehmen und abspielen kann [3], und einem Mock Verfikationssystem, das eine Verfikation von Anfragen zu asynchronen Aufrufen an den Mock Server ermöglicht [4].

In den meisten Fällen reicht ein einfacher Request Response Mock Stub. Solch eine Definition könnte wie folgt aussehen, z.B. für einen HTTP Mock:

{
  "port": 8010,
  "protocol": "http",
  "name": "My Mock",
  "mode": "text",
  "stubs": [
    {
      "responses": [
        {
          headers: {
            'Content-Type': 'text/xml'
          },
          body: "..."
        }
      ],
      "predicates": [
        {
          "and": [
            {
              "equals": {
                "path": "/MyService/MyOperation"
              }
            },
            {
              "contains": {
                "body": "Mountebank"
              }
            }
          ]
        }
      ]
    }
  ]
}

Der Stub würde am Port 8010 auf einen HTTP Call warten. Wenn die Prädikate zutreffen, in diesem Fall ein Aufruf von /MyService/MyOperation welches den String „Mountebank“ im POST Body enthalten würde, wird eine HTTP Response mit dem HTTP Content-Type „text/xml“ und dem Body „…“ gesendet.

Diese Definition kann an Mountebank entweder über das UI, das von Port 2525 erreichbar ist, über die REST API oder während des Applikationsstarts übergeben werden.

Mockdaten-Dateistruktur

Wenn die Applikation gestartet wird, kann eine Konfigurationsdatei automatisch an die Mountebank Instanz über die REST API gesendet werden.

Da solch eine Mockdaten-Datei viele verschiedene Stubs enthalten und dementsprechend groß und kompliziert werden kann, ist eine Vereinfachung notwendig. Diese ist möglich durch die Integration von JavaScript EJS Templating. Es kann verwendet werden, um eine größeren Mock-Datensatz bestehend aus mehreren Dateien und verschiedenen Ordern zu erstellen.

Die Hauptdatei „imposters.ejs“, die eine Liste für den Import von Mock Unterordnern für solch einen großen Mock Datensatz enthalten würde, könnte wie folgt aussehen:

{
  "port": 8010,
  "protocol": "http",
  "name": "NKD Mock",
  "mode": "text",
  "stubs": [
    <% include myServiceA/imposters.ejs %>,
    ...
  ]
}

Dabei würde im Unterordner die Datei „myServiceA/imposters.ejs“, welche die Stubs und Responses definiert, abgelegt werden. Zur weiteren Reduktion der Komplexität können diese wieder in separate Dateien ausgelagert werden:

{
  "responses": [
    {
      "inject": "<%- stringify(filename, 'myServiceA/responseA.ejs') %>"
    }
  ],
  "predicates": [
    {
      "and": [
        {
          "equals": {
            "path": "/MyService/MyOperation"
          }
        },
        {
          "contains": {
            "body": "Mountebank"
          }
        }
      ]
    }
  ]
},
{
  "responses": [
    {
      "inject": "<%- stringify(filename, 'myServiceA/default.ejs') %>"
    }
  ],
  "predicates": [
    {
      "equals": {
        "path": "/MyService/MyOperation"
      }
    }
  ]
}

In diesem Fall haben wir außerdem einen Standardfall, der greift, falls die anderen Prädikate nicht erfolreich evaluiert werden.

Die Response wird als Json-Objekt von eine JavaScript-Funktion aus der Reponse-Datei „myServiceA/default.ejs“ zurück gegeben:

function() {
  return {
    headers: {
    'Content-Type': 'text/xml'
  },
    body: "..."
  };
}

Docker

Docker ist eine Open-Source-Technologie, die Virtualisierung von Maschinen in isolierten Containern auf einem Betriebssystem ermöglicht. Durch die Verwendung von Linux-Technologien wie Cgroups und Namespaces erlaubt es das schnelle und Ressourcen effiziente Erzeugen von Virtuellen Maschinen, womit man eine portable, nachvollziehbare und konsistente Infrastruktur aufbauen kann. Dies ist vor allem für die Erstellung, Durchführung und Nachvollziehbarkeit von Test-Szenarien, die infrastrukturbasiert sind, ein großer Vorteil.

Bauen des Mock Servers

Um ein Docker Image für dieses Szenario zu bauen, das die Mock Daten des Mock Servers bereits enthält, benutzen wir ein Docker Image, das Mountebank vorinstalliert hat und im Docker Repository verfügbar ist. Unsere Dockerfile würde wie folgt aussehen:

FROM                    cpoepke/mountebank-basis:latest

  • Seite
  • 1
  • 2

Conrad ist Business Development Manager bei der codecentric AG. Er sieht sich selbst als „Coding-Software-Architekt“, Entwickler und in allen anderen Rollen, die für die erfolgreiche Durchführung eines Projekts vonnöten sind. Derzeit fokussiert er sich auf dem Aufbau der Partnerschaft mit Amazon Web Services und auf die in dem Rahmen entstehenden Projekte. Sein persönliches Ziel ist es, nach neuem Wissen in der IT-Industrie zu streben.

In seiner Freizeit macht er sich in Berlin für die IT Community stark, als Gründer und Hauptorganisator des Microservices Meetups Berlin, Co-Organizer des DDD Meetups, des Serverless Meetups und als Mitglied im Organisations-Komitee der MicroXchg Konferenz und KanDDDinsky der Berliner DDD Konferenz.

Share on FacebookGoogle+Share on LinkedInTweet about this on TwitterShare on RedditDigg thisShare on StumbleUpon

Kommentieren

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.