Citrus – Integrationstests für Schnittstellen

By | 19. Oktober 2015

Eine wesentliche Herausforderung beim Schreiben von Integrationstest für integrierte Software-Systeme ist die Kommunikation mit externen Systemen. In machen Fällen bieten die externen Systeme eine Test- bzw. QS-Umgebung gegen die getestet werden kann. Aber auch in diesem Fall kann nicht sichergestellt werden, dass die externen Systeme immer auf die gleiche Weise reagieren. Die geschriebenen Testfälle sind somit nicht stabil und neigen dazu fehlzuschlagen, auch wenn kein Fehler im der eigenen Software existiert – die Ergebnisse sind nicht deterministisch.

Lange Zeit habe ich nach einem Lösungsansatz für dieses Problem gesucht und bin schließlich auf das Citrus Framework gestossen. Vor Allem im Zusammenhang mit einer größeren Integrationsprojekt (i.e.S. Enterprise Service Bus / ESB) hat sich dieses Framework für mich als unentbehrlich herausgestellt. Ich möchte darum hier einen kurzen Überblick geben.

Wie funktioniert Citrus?

Typischer Weise sieht ein Integrationsszenario an dem externe Systeme beteiligt sind so aus:

Mit Hilfe von Citrus wird es möglich, die Verhaltensweise und die Schnittstellen des externen System komplett zu simulieren. Citrus bietet diverse Protokolle und Formate an:

  • Protokolle
    • SOAP
    • JMS
    • REST
  • Formate
    • JSON
    • XML
    • CSV

Citrus kann sowohl die Rolle des Clients – aufrufendes System – als auch die Rolle des Servers – aufgerufenes System – einnehmen.

Funktion des Citrus-Framework in Anlehnung an http://www.citrusframework.org/

Einrichtung mit Maven

Das Citrus-Framework kann am einfachsten mit Hilfe einer einfachen Maven-Dependency eingebunden werden.

Zunächst müssen die Repositories eingebunden werden:

Dann werden die Dependencies hinzugefügt:

Testfälle

Ein Testfall ist immer nach dem folgenden Muster aufgebaut:

Zunächst wird eine Nachricht an zutestende System geschickt und dann von einem externen Zielsystem empfangen. Sowohl der aufrufende Client als auch das externe System wird durch Citrus-Endpunkte simuliert. Zumeist werden mehrere Endpunkte in einem Ablauf verwendet.

Die Implementierung von Testfälle ist mittels XML-Konfiguration oder Java möglich. Ich favorisiere die Java-Implementierung auf Grund der Code-Überprüfung.

 

Implementierung eines Testfalls

 

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.testng.annotations.Test;

<span class="hl-keyword">import</span> com.consol.citrus.dsl.testng.TestNGCitrusTestDesigner;

import com.consol.citrus.dsl.annotations.CitrusTest;
import com.consol.citrus.http.client.HttpClient;
import com.consol.citrus.jms.endpoint.JmsSyncEndpoint;
import com.consol.citrus.message.MessageType;

public class HTTPTest extends TestNGCitrusTestDesigner {

    @Autowired
 // HTTP-Client; eine Anfrage wird an einer HTTP-Endpunkt gesendet und eine Antwort empfangen
    private HttpClient serviceClient;

    @Autowired
 // Synchroner JMS-Endpunkt; eine Nachricht wird in aus einer Queue empfangen und über eine Reply-Queue wird die Antwort synchron gesendet
    protected JmsSyncEndpoint jmsQueue;

    @Test
    @CitrusTest
    public void testArtikelstammNormal() {

        // Senden: Die Anfrage an einen HTTP-Enpunkt senden
        send(servicesHttpClientDez).http().method(HttpMethod.POST).path("/services/testService").messageType(MessageType.PLAINTEXT)
                .fork(true).payload("This is the request");
        
        // Empfangen: Die Anfrage in einer JMS-Queue empfangen
        receive(queue)
                .messageType(MessageType.PLAINTEXT)
                .payload("This is the request")
                .extractFromHeader("citrus_jms_correlationId", "correlationId");

        // Senden: Die Antwort synchron an die JMS-Reply-Queue senden
        send(queue).messageType(MessageType.PLAINTEXT).header("citrus_jms_correlationId", "${correlationId}").payload("This is the response");

        // Empfangen: Die Antwort über den HTTP-Client empfangen
        receive(servicesHttpClientDez)
                .messageType(MessageType.PLAINTEXT)
                .payload("This is the response");

    }

} 

Schreibe einen Kommentar

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