Individuelle Wünsche der Kunden stellen einen Entwickler immer wieder aufs Neue vor Herausforderungen bei der Konzipierung neuer Systemlösungen. Häufig müssen Technologien entsprechend modelliert und angepasst werden, um den Anforderungen des Kunden nachzukommen. Unsere Consultants und Engineers konzipieren im Projektgeschäft passgenaue IT-Lösungen entsprechend der Wünsche im Kundenauftrag. Hierbei setzen wir auf die Produkte unserer Technologiepartner: Als wertvolles Tool für das Datenmanagement haben sich die Softwarelösungen von Talend bewährt, die wir strategisch kombinieren und nach den Anforderungen des Kunden anpassen. Im Anschluss an die Ausarbeitung des Lösungskonzepts steht die Entwicklung des Prototypen im Vordergrund. Um eine möglichst überzeugende Lösung anbieten zu können, setzen datenzentrierte Tests das Fundament bei der abschließenden Vorstellung.

In dieser dreiteiligen Themenreihe beschäftige ich mich mit den verschiedenen Möglichkeiten, datenzentrierte Tests in Talend durchzuführen.

Warum datenzentrierte Tests essentiell für die Entwicklung komplexer Software sind

Für die Entwicklung komplexer Software wird häufig Continuous Integration und Continuous Delivery angestrebt. Dies beinhaltet das automatische Bauen und Testen von Softwarekomponenten. Das automatisierte Testen sorgt einerseits für stabilere Releases, andererseits gibt es dem Entwickler auch Sicherheit während der Neuentwicklung und des Refactorings. Ein neues Feature wird häufig erst als fertig bezeichnet, wenn auch eine entsprechende Testabdeckung vorhanden ist. Dabei gibt es Tests auf verschiedenen Ebenen. Es wird häufig von Unit-, Komponenten-, Integrations- und End-to-End-Tests gesprochen.

Verschieden Test-Arten im Überblick

  • Ein Unittest testet einen einzelnen atomaren Teil einer Software, wie z.B. eine Methode oder einen Schritt in einem Talend-Job. Dabei werden äußere Einflüsse durch definierte Ein- und Ausgaben gemocked.
  • Komponententests testen eine Softwarekomponente im Ganzen. Hier wird das Zusammenspiel der einzelnen Teile innerhalb der Komponente überprüft. Einflüsse, die von außerhalb kommen werden auch hier gemocked. Was als Softwarekomponente betrachtet wird, ist definitionsabhängig. Praktikabel ist es unabhängig deploybare Einheiten als Komponente zu bezeichnen.
  • Integration- und End-to-End-Tests prüfen das Zusammenspiel von einzelnen Komponenten, wie z.B. UIs, Backend-Services, Datenbanken und Talend-Jobs.

Unit Tests werden von Talend unterstützt

Für Komponenten wie UIs oder Backend Services gibt es eine ganze Reihe von Tools, die einem das Entwickeln von Tests auf den verschiedenen Testebenen ermöglichen. Auch Talend bietet eine integrierte Möglichkeit Unit-Tests für einzelne Schritte eines Jobs zu erstellen. Für die anderen Testebenen wird allerdings keine Unterstützung bereitgestellt.

Eine Möglichkeit einen Talend-Job zu testen wäre es, einen dedizierten Test-Job zu schreiben. Dieser müsste über Context-Parameter alle äußeren Einflüsse, wie DBs, Services und File-Shares auf eine Testumgebung umbiegen, diese Testumgebung mit definierten Testdaten füllen und nach dem Ablauf des Jobs die Ergebnisse mit den gewünschten Ergebnissen vergleichen. Dies ist für Datenbanken und File-Shares noch recht einfach möglich. Für Services wird dies bereits aufwändiger.

Wie Sie alternative Testmethoden in Talend umsetzen

In diesem Blog-Post soll nun eine alternative Möglichkeit des Testens mit JUnit vorgestellt werden, die bekannte Tools aus dem Java Umfeld für das Testen von Backend-Services verwendet. Es wird dabei davon ausgegangen, dass ein Nexus für das Verwalten von Artefakten vorhanden ist und dieser mit den Talend Jobs (evtl. über eine Jenkins-Pipeline) befüllt wird.

Ein Talend-Job ist letztlich ein Jar, das mit seinen Abhängigkeiten und seinen Context-Parametern in einer Zip-Datei vorliegt. In einem Java-Projekt, dass zum Testen des Jobs mit JUnit dienen soll, kann dieses Zip mit dem Build-Tool Gradle folgendermaßen heruntergeladen und entpackt werden:

apply plugin: 'java'

configurations {
    zipped
}

repositories {
    mavenCentral()
    <local nexus>    
}

dependencies {
    ...
    zipped group: 'com.example', name: 'test-testing', version: '0.1.0-SNAPSHOT', ext: 'zip'
    testImplementation files({ tasks.installDependencies.extractedJars })
}

task installDependencies(type: Sync) {
    def extractDir = "${buildDir}/my-libs"

    ext.extractedJars = fileTree(extractDir) {
        include "**/*.jar"
        builtBy "installDependencies"
    }

    dependsOn configurations.zipped
    from {
        configurations.zipped.collect { zipTree(it) }
    }
    into extractDir
}

 

Dieses Gradle-Script lädt den Talend-Job aus dem Nexus herunter, entpackt alle JARs aus dem ZIP und fügt sie dem Classpath hinzu. Mit dem Build-Tool Maven ist dies auch möglich mit dem maven-dependency-plugin und dem unpack-dependencies Schritt. Um die JARs dann dem Classpath hinzuzufügen, müssen die Abhängigkeiten noch mit dem maven-install-plugin in ein lokales Repository installiert werden.

Ein einfacher JUnit-Test kann den Talend Job folgendermaßen aufrufen und die Context-Parameter beeinflussen um äußere Abhängigkeiten zu mocken:

TestJob talendJob = new TestJob();
String [] context=new String[] {"--context_param JdbcUrl=...",
                                "--context_param url=..."
                };
talendJob.runJob(context);

 

Alternativ lässt sich der Context auch dadurch beeinflussen, dass ein Test-Context-Script in den Test-Ressourcen abgelegt wird. Abhängig davon für welche äußeren Abhängigkeiten letztlich Mocks eingesetzt werden, können mit dieser Technik Komponenten-, Integrations- und End-to-End-Tests umgesetzt werden.

Fazit: Einsatz von automatisierten Tests in Talend

In diesem Blogeintrag wurde nach einem Überblick über die Begriffe des automatisierten Testens gezeigt, dass sich ein Talend Job leicht in einer klassischen JUnit Testumgebung testen lässt. Diese Tests können dann leicht in eine Jenkins Build-Pipeline integriert werden, um kontinuierlich die Software-Qualität zu überwachen.

Im nächsten Artikel zu dieser Reihe gehe ich darauf ein, wie mit DbUnit und WireMock Testdatensätze und Mockserver verwendet werden können.