Testgetriebene Entwicklung und Testautomatisierung mit Talend

Testgetriebene Entwicklung und Testautomatisierung

Eine Kernaufgabe unserer Data Warehouse (DWH) Projekte besteht darin, Daten aus verschiedenen Quellen ins DWH und über verschiedene Ebenen innerhalb zu transportieren. Auf diesem Weg müssen diese Daten meist angereichert oder transformiert werden. Diesen Prozess bezeichnet man als „Extract, Transform & Load“ (ETL). Für die Entwicklung dieser ETL-Prozesse setzen wir häufig auf Talend Data Integration. Talend Jobs werden entwickelt, getestet, deployt und laufen dann regelmäßig, um diese ETL-Aufgaben zu übernehmen – sie machen buchstäblich ihren Job.

Doch was passiert, wenn sich die Anforderung an den Job ändert? Bei Logikänderungen, Technologiewechsel, Upgrades oder aus diversen anderen Gründen müssen Jobs angepasst und neu bereitgestellt werden.

Testgetriebene Entwicklung in der Praxis

Für diese Anpassungen ist es sinnvoll bereits von Beginn an Tests zu definieren, um in der Lage zu sein, die korrekte Funktionsweise der Jobs jederzeit zu gewährleisten.

In der klassischen Softwareentwicklung ist das Testen hintenangestellt. Zuerst wird der Code (Talend Job) geschrieben und danach erfolgen die Tests. Das führt oft dazu, dass unter Zeitdruck gearbeitet wird, Programmierer nachlässig werden oder um bekannte Eigenheiten herumtesten. Kurzum: Die Testqualität leidet darunter und damit auch die Qualität der Software.

In der agilen Softwareentwicklung geht man iterativ vor und entwickelt kleine Inkremente. Das betrifft auch das Testen: Man testet jedes einzelne Inkrement statt erst nach Fertigstellung der kompletten Software.

Und mehr noch: „Test first!“ ist die Devise. Man geht testgetrieben vor, schreibt also zuerst den Test und danach den Code. Schlägt der Test dann fehl, wird analysiert und korrigiert (Code oder Test) – solange bis alles wie erwartet funktioniert. Bei dieser Vorgehensweise wird der Tests auf der Basis der Anforderungen geschrieben statt auf Basis der Code-Logik.

In der Praxis kann das auch gut und gerne parallel passieren. Empfehlenswert ist auch, dass ein Teammitglied den Code und jemand anderes den Test schreibt. Somit erhört sich das gemeinsame Verständnis für die Software und es werden schneller und besser Fehler entdeckt. Das sollte nicht in einer klassischen Rollenverteilung (Entwickler vs. Tester) passieren, sondern jeder im Team kann abwechselnd eine der beiden Rollen übernehmen.

Unit Tests mit Talend

Mit Version 6 hat Talend das Unit Test Feature eingeführt (im Talend Open Studio nicht verfügbar). Mit diesem lassen sich für Teile eines Talend Jobs Tests definieren und ausführen. Um einen Unit Test zu erstellen, wählt man wie in Abbildung 1 im Talend Studio Designer die Komponente(n) aus, die man testen möchte.

Bildmodul

Abbildung 1: Talend Unit Test erstellen

Das können eine oder mehrere Komponenten sein, die in einem Subjob per Row hintereinander gereiht sind, wo also Daten verarbeitet werden. Per Rechtsklick auf die markierten Komponenten lässt sich dann über „Create Test Case“ eine Testfall-Vorlage (Skeleton) erstellen. Diese Vorlage muss dann in wenigen Schritten angepasst werden.

Bildmodul

Abbildung 2: Talend Unit Test Skeleton

Die Vorlage beinhaltet mehrere Subjobs (Abbildung 2):

1) Zunächst wird eine temporäre Datei erstellt (tCreateTemporaryFile), die nach Ausführung automatisch wieder gelöscht wird.

2) Der mittlere Teil beinhaltet die zu testenden Komponenten, die durch INPUT und OUTPUT Eckpunkte abgegrenzt sind. Diese Komponenten können nur im eigentlichen Job angepasst werden, an dieser Stelle sind sie unveränderbar.

Für den Test wird eine definierte Input-Datei über tFileInputDelimited eingelesen (je nach ausgewählten Komponenten können das auch mehrere sein). Die Daten werden in den zu testenden Komponenten verarbeitet und in die temporäre Datei geschrieben.

3) Zuletzt wird die temporäre Datei mit einer Referenzdatei verglichen (tFileCompare) und per tAssert ausgewertet. Stimmt das Ergebnis nicht mit dem erwarteten Ergebnis überein, so schlägt der Test fehl.

Die Inhalte der Testdaten werden über Kontextvariablen gesteuert. Man muss nun Testdaten über die Test Cases Ansicht hinterlegen (Abbildung 3).

Bildmodul

Abbildung 3: Talend Unit Test konfigurieren

Pro Test Case Instanz (hier „Default“) erstellt man mindestens eine Inputdatei und eine Referenzdatei an einem beliebigen Ort im lokalen Filesystem. Nach dem Laden im Talend Studio werden diese automatisch im Repository abgelegt und versioniert. Wichtig ist, darauf zu achten, dass die Eigenschaften der Dateien (z.B. Feldseparator) zu den Einstellungen der Komponenten passen.

Es lassen sich auch mehrere Instanzen hinzufügen, wenn man mit verschiedenen Input-Daten testen möchte. Über „Run Test Case“ wird der Test dann ausgeführt und zeigt im Erfolgsfall einen grünen Balken an. Möchte man im Job etwas ändern und danach testen, sollte man den eigentlichen Job und den Unit Test immer getrennt öffnen. Ansonsten kann es sein, dass die Logikänderung noch nicht im Unit Test synchronisiert ist.

Mit Unit Tests kann man also Teile eines Jobs testen. Schwierig wird es an Stellen ohne Datenfluss (z.B. tJava- oder tDBRow-Komponenten), sowie den Schnittstellen zu externen Komponenten. Ein Job, der eine Datei einliest und in eine Datenbanktabelle schreibt, lässt sich beispielsweise schwer mit Unit Tests abdecken. Man ergänzt die Unit Tests also um (Komponenten-)Integrationstests, um den Job als Gesamtpaket zu testen. Wie lassen sich diese Integrationstests für einen Talend Job umsetzen?

Integrationstests mit Robot Framework

Denkbar wäre, dass man dafür einen dedizierten Talend Job schreibt, der ähnlich aufgebaut ist wie ein Unit Test: Ein Setup-Teil, der Input-Daten bereitstellt und die Zieltabelle vorbereitet, einen Teil der den zu testenden Job ausführt und einen Teil, der das Ergebnis prüft.

Besser eignen sich hierfür dedizierte Test-Tools, denn diese bringen viele nützliche Features bereits mit, wie z.B. Reporterstellung (s.u.). Implizit lassen sich dort auch Abhängigkeiten von Jobs besser testen.

Robot Framework ist ein generisches Open Source Automatisierungs-Framework. Das Framework ist in Python implementiert und leicht erweiterbar (auch in anderen Sprachen wie Java). Testskripte verwenden eine natürliche Sprache, sodass besser klar wird was im Test passiert. Man kann vorhandene Keyword-Bibliotheken benutzen, kombinieren und damit bereits sehr viel grundlegendes eines Talend Jobs testen.

Bildmodul

Abbildung 4: Aufbau eines Robot Framework Testskripts

In einem Testskript definiert man (beispielsweise pro Talend Job) das Setup und Teardown, die Testfälle und mögliche lokale Methoden (Keywords). Es gliedert sich in die Abschnitte Settings, Variables, Test Cases und Keywords (siehe Abbildung 4).

Im Settings Abschnitt werden u.a. Bibliotheken importiert und das Setup festgelegt. Im Beispiel ist das Setup für die gesamte Testsuite (diese Datei) das Keyword „Prepare Environment“.

Dieses Keyword ist in derselben Datei im Keywords-Abschnitt definiert und beinhaltet wiederum die Keywords „Setup Environment For Talend Jobs“, „Setup Postgres Database“ und „Setup Testdata“. Die Keywords sind soweit abstrahiert, dass sie nur beschreiben was das Ziel dieser ist. Wenn nötig, kann man aber jeweils die Keyword Definition öffnen, bis man sieht was wirklich ausgeführt wird.

Bildmodul

Abbildung 5: Keyword-Definition von Setup Postgres Database

Im Keyword „Setup Postgres Database“ wird z.B. per SQL Statements das Schema angelegt wird, falls es noch nicht existiert, und die Tabelle in jedem Fall neu erzeugt (Abbildung 5). So wird sichergestellt, dass sich die Zieltabelle des Jobs in einem bekannten Zustand befindet. Dies ist das Ziel für das gesamte Setup: einen bekannten Ausgangszustand für alle beteiligten Systeme herstellen, sodass man den Endzustand vorhersagen kann.

Im Abschnitt Test Cases sind dann die eigentlichen Testfälle definiert. Im Beispiel ist der Name des Testfalls „Load Data To Names Table“. In diesem Testfall wird dann der Talend Job ausgeführt und die Anzahl und der Inhalt der Tabelle geprüft (Abbildung 4).

Der Test lässt sich nun entweder über die Kommandozeile per „robot test-suites/01__ETL/03__demo_tMapLookup.robot“ ausführen oder man hat im Editor (hier Visual Studio Code mit Robot Framework Language Server Plugin) Unterstützung, um die Tests per „Run Button“ auszuführen (siehe Abbildung 4). In jedem Fall wird am Ende ein Report erzeugt, der anzeigt wie der Test gelaufen ist.

Bildmodul

Abbildung 6: Robot Framework Testreport

Testautomatisierung

Nun hat man für den Talend Job einen Unit Test und einen Integrationstest definiert, die man jederzeit wieder ausführen kann, um Änderungen zu testen. Denkt man noch einen Schritt weiter, so lässt sich der komplette Prozess bis hin zur Auslieferung oder sogar Produktivsetzung  des Artefakts automatisieren (Continuous Delivery bzw. Continuous Deployment). In diesen Prozess fällt dann eben auch die Ausführung der Tests, sodass man eine Pipeline erstellen kann, die alle Schritte übernimmt.

Bildmodul

Abbildung 7: Continuous Deployment Pipeline

Zunächst wird das Artefakt aus dem Source Code gebaut, sodass eine ausführbare Datei entsteht. Bei Talend kann man hierbei bereits auswählen bzw. angeben, dass die Unit Tests mit ausgeführt werden sollen. Schlagen diese fehl, läuft die Pipeline nicht weiter und der Fehler muss erst behoben werden. Im Erfolgsfall wird das Artefakt in einem Artefakt Repository abgelegt. Dieses wird auf eine Testumgebung deployt, wo die Integrationstests nun ausgeführt werden können. Sind diese ebenfalls erfolgreich gelaufen, kann das Artefakt in Produktion deployt werden. Dieser Prozess ist nur eine vereinfachte Darstellung. Je nach Deployment-Prozess gibt es möglicherweise noch mehrere Zwischenschritte, die ausgeführt werden.

Für die Realisierung einer solchen Pipeline gibt es einige Tools, die man nutzen kann. Im Open Source Bereich wird oft Jenkins verwendet. Je nachdem welcher Anbieter aber bereits für die Quellcodeverwaltung im Unternehmen ist, gibt es beispielsweise mit GitLab CI auch von GitLab ein Tool, mit dem man eine Pipeline definieren kann. Dies erfolgt ebenfalls in einem Skript (z.B. yaml), welches im Repository abgelegt und versioniert wird.

Fazit

Möchte man die Softwarequalität seiner Talend Jobs steigern, so empfiehlt es sich auf eine Kombination von Talend Unit Tests und Integrationstest mit einem zusätzlichen Tool, wie Robot Framework, zu setzen. Mit den Unit Tests lassen sich kleine Einheiten eines Jobs im Detail testen. Ergänzend dazu stellt man mit Integrationstests die komplette Funktionsweise eines Jobs, insbesondere die Interaktion mit externen Komponenten (z.B. Datenbank), sicher. Mit diesen wiederausführbaren Tests und bestenfalls einer automatischen Ausführung innerhalb einer Build-Pipeline, lässt sich die Softwarequalität steigern und die Entwicklungsgeschwindigkeit langfristig erhöhen.

Kontakt

Rouven Homann
Managing Partner

Telefon: +49 (0)40 53302-444
E-Mail: rouven.homann@cimt-ag.de
Twitter: twitter.com/cimtag

Download

Erfahren Sie mehr darüber, welche Möglichkeiten Talend im Bereich Testen bietet, wie sich das Ökosystem hierbei sinnvoll erweitern lässt und wie eine Testautomatisierung für Jobs aussehen kann. Jetzt Video (50 Minuten) mit Live-Demo anfordern:






    Sie erhalten das Video, sofern Sie einwilligen, dass wir Ihre E-Mail-Adresse zukünftig für Marketingzwecke nutzen dürfen. Die werbliche Nutzung Ihrer E-Mail-Adresse ist somit Ihre Gegenleistung für den Erhalt des Videos. Diese Einwilligung können Sie selbstverständlich jederzeit widerrufen.

    Kommende Veranstaltungen
    div#stuning-header .dfd-stuning-header-bg-container {background-image: url(https://www.cimt-ag.de/wp-content/uploads/2017/10/home-start2_low.jpg);background-color: #848484;background-size: cover;background-position: center center;background-attachment: fixed;background-repeat: no-repeat;}#stuning-header div.page-title-inner {min-height: 300px;}div#stuning-header .dfd-stuning-header-bg-container.dfd_stun_header_vertical_parallax {-webkit-transform: -webkit-translate3d(0,0,0) !important;-moz-transform: -moz-translate3d(0,0,0) !important;-ms-transform: -ms-translate3d(0,0,0) !important;-o-transform: -o-translate3d(0,0,0) !important;transform: translate3d(0,0,0) !important;}