Zum Inhalt springen

Suchen...

COBOL-Unit-Tests: Java-Tests laufen im Mainframe-Debugger

COBOL-Unit-Tests schreiben viele Entwickler lieber in Java. Ein Tool übersetzt sie in Debugger-Skripte und bindet Jenkins und SonarQube an.

• • Aktualisiert: • 10 Min. Lesezeit
Cover zum Expertengespräch über 'COBOL-Unit-Tests: Java-Tests laufen im Mainframe-Debugger' mit Bartosz Filipek, Szymon Wałachowski und Richard Seidl.

COBOL-Unit-Tests auf einem Mainframe, der über Jahrzehnte angepasst wurde, lassen sich mit Standardwerkzeugen nicht umsetzen. Die Lösung ist eine Java-API, die Testlogik in Debugger-Skripte übersetzt, die der Mainframe direkt ausführt. So bekommen alte COBOL-Programme Anschluss an Standardwerkzeuge wie SonarQube, Cucumber und Jenkins, und COBOL-Entwickler schreiben Assertions in Java, ohne die Sprache kennen zu müssen.

Das Wichtigste in Kürze

  • Eine letzte, gut durchdachte Anpassungsschicht, die eine Legacy-Umgebung an Standardwerkzeuge anbindet, trägt länger als Ad-hoc-Anpassungen, die sich immer weiter stapeln.
  • COBOL-Entwickler fanden es einfacher, Assertions für Unit-Tests in Java zu schreiben als in COBOL selbst, weil die Java-API keine Java-Vorkenntnisse voraussetzt.
  • Fehlt in einem Legacy-Stack die Möglichkeit, Unit-Tests zu schreiben, zieht das weitere Lücken nach sich: Reporting, Release-Absicherung und die Anbindung an Werkzeuge wie SonarQube und X-Ray fallen mit weg.
  • Codeabdeckung für COBOL-Programme lässt sich über die eingebaute Zeilenverfolgung des IBM-Debuggers messen, ganz ohne eigene Implementierung.

Warum Individualsoftware Anpassung auf Anpassung stapelt

Individualsoftware wächst in Schichten. Eine Speziallösung zieht die nächste nach sich, und irgendwann sind die Schichten so verknäult, dass kein Standardwerkzeug mehr herankommt.

Das ist die Falle hinter einem System, das sich schon vor Jahrzehnten von Standards und Best Practices verabschiedet hat. Gibt es eine Funktion nicht am Markt, baut das Unternehmen sie selbst. Diese erste Entscheidung wirkt wie ein Einzelfall, bleibt es aber selten.

Szymon Wałachowski beschreibt den Mechanismus ohne Umschweife. Führst du eine Anpassung ein, brauchst du eine zweite obendrauf. Baust du genug solcher Schichten, steckst du in einem Geflecht aus Anpassungen, aus dem es keinen klaren Ausweg gibt.

Bei einem Unternehmen, das seit sechzig Jahren besteht, reicht diese Geschichte weit zurück. Manche Entscheidungen haben Menschen getroffen, bevor die heutigen Entwickler geboren wurden. Wer verstehen will, warum die Umgebung so aussieht, wie sie aussieht, muss Generationen von Entscheidungen zurückverfolgen.

Mainframe-Tests: Ein fehlendes Werkzeug blockiert alles Nachgelagerte

Fehlt ein Baustein in der Toolchain, fehlen auch alle Bausteine, die darauf aufsetzen.

Das Unternehmen konnte die Standardwerkzeuge von IBM für COBOL-Unit-Tests nicht nutzen. Diese eine Lücke reichte weit über die Unit-Tests hinaus. Ohne automatisierte Tests gab es kein Reporting. Ohne eine Möglichkeit, die Korrektheit einer Änderung zu prüfen, wurde jedes Release riskanter.

Die Abhängigkeit läuft nur in eine Richtung. Reporting, Testabdeckung und Vertrauen ins Release lassen sich nicht auf einer Testfähigkeit aufbauen, die es gar nicht gibt. Das Fehlen von Unit-Tests hat also eine ganze Reihe von Praktiken mitgerissen, die für ein modernes Team selbstverständlich sind.

Genau das sind die echten Kosten von Legacy und technischen Schulden. Es geht nicht nur um alten Code. Es geht um die Kette von Fähigkeiten, die du nicht aufbauen kannst, weil das Fundament darunter nie gelegt wurde.

Das fehlende Werkzeug selbst bauen und an die Standardwelt anschließen

Die Lösung: das fehlende Werkzeug im Haus selbst schreiben, in Java, und es als Brücke zu den marktüblichen Werkzeugen nutzen.

Weil das Unit-Test-Tool für COBOL in Java geschrieben ist, konnte das Team Werkzeuge anbinden, zu denen die Mainframe-Welt sonst keinen Zugang hat. Cucumber, Jenkins, Allure, SonarQube und X-Ray wurden damit erreichbar. Das hauseigene Tool ist das Bindeglied zwischen Mainframe und gängiger Toolchain.

Für Szymon ist das die eine Anpassung, die den Kreislauf beendet. Frühere Anpassungen haben weitere Anpassungen erzeugt. Diese bewirkt das Gegenteil. Sobald du dich an alles anbinden kannst, musst du nicht mehr für jeden neuen Bedarf eine Speziallösung bauen.

“Eigentlich haben wir eine letzte Anpassung gebaut, die den Arbeitsablauf ab jetzt umstellen soll. Weil du jetzt alles anbinden kannst, solltest du danach keine weiteren Anpassungen mehr bauen müssen.”

(Szymon Wałachowski)

Bartosz Filipek nennt es eine Schnittstelle zur Standardwelt. Das Bild passt. Das Tool legt keine weitere verknäulte Schicht obendrauf. Es öffnet eine Tür, durch die das Team alles erreicht, was draußen liegt.

So funktionieren COBOL-Unit-Tests über den Debugger

Du schreibst den Test in Java, und ein Übersetzungsschritt macht daraus ein Skript, das der Mainframe-Debugger ausführt.

Java war eine bewusste Wahl. Java bringt von Haus aus komfortable Werkzeuge mit, COBOL nicht. Unit-Tests direkt in COBOL zu schreiben, wäre zu mühsam gewesen, also nahm das Team die Sprache, die Entwicklern ohne Zusatzaufwand mehr bietet.

Die Java-Seite ist so gebaut, dass du kein Java können musst. Du folgst den Klammern, öffnest und schließt sie, setzt ab und zu einen Punkt und trägst einfache Literale ein, etwa einen Variablennamen und einen Wert. Mehr braucht es nicht, um einen Testfall zu formulieren.

Anschließend wird der Java-Test in ein Debug-Skript übersetzt. Der Mainframe startet das Programm im Debug-Modus, und das Skript steuert die Testlogik. Es hält an definierten Stellen an, mockt Werte dort, wo du es festgelegt hast, und prüft Werte an bestimmten Punkten.

Weil alles über den Debugger läuft, kannst du fast überall anhalten und fast überallhin springen. Diese Freiheit eröffnet sehr viele Möglichkeiten, ein Programm zu testen.

Assertions sind sprachunabhängig

Eine Assertion ist etwas Abstraktes. Du nimmst eine Variable und vergleichst sie mit einem Wert. Dieser Logik ist egal, ob der Code drumherum Python, COBOL oder Java ist.

Für die COBOL-Entwickler ist Java deshalb nur das Mittel, um die gewünschte Prüfung auszudrücken. Die IDE prüft die Syntax von selbst und schlägt vor, was an welche Stelle gehört, indem sie Argumentnamen und JavaDocs ausliest.

Warum COBOL-Entwickler ihre Tests lieber in Java schreiben

Die COBOL-Entwickler fanden es einfacher, Tests und Assertions in Java zu schreiben als in COBOL, obwohl COBOL ihre erste Programmiersprache ist.

Das hat Szymon überrascht. Eine externe Firma hielt einen Workshop zu einem Tool, mit dem man Unit-Tests in COBOL schreibt, und er rechnete damit, dass dieses Tool mit seiner Vertrautheit punktet. Die COBOL-Entwickler im Workshop sahen es umgekehrt. Dank der einfachen API war Java für sie der leichtere Weg.

Der Grund steckt in der Syntax. Assertions in COBOL brauchen viel Text und viel Boilerplate. Der Klartext ist schwer zu pflegen und schwer zu lesen. In Java kommen dieselben Assertions mit weniger Zeichen aus.

Bartosz verweist auf die Programme selbst. Ein kompiliertes COBOL-Programm kann hunderttausend Zeilen lang sein. In Java zeigt der Test direkt auf die Abschnitte, die als Funktionen dienen, und auf die Variablen, die geprüft werden. Diese Genauigkeit ist in einem ausufernden COBOL-Quelltext kaum zu erreichen.

Dazu kam das Arbeitsgefühl. Die IDE prüfte die Syntax, gab Hinweise und validierte Argumente schon beim Tippen. So etwas hatte der COBOL-Workflow nie geboten.

Testabdeckung für COBOL liefert der Debugger gratis

Der Mainframe-Debugger kann mitschreiben, welche Zeilen ausgeführt wurden. Die Daten für die Codeabdeckung fallen also ohne Zusatzaufwand aus dem bestehenden Setup heraus.

Du schaltest im Debugger eine Option ein, er protokolliert die ausgeführten Zeilen und gibt Statistiken aus. Jeder Test deckt einen anderen Teil des Codes ab, die Ergebnisse müssen also zusammengeführt werden. Die Rohdaten liegen aber schon bereit.

Was noch fehlt, ist nicht technischer Natur, sondern Abstimmung. Der Code gehört den COBOL-Entwicklern, und es gibt unternehmensspezifische Spielregeln, die das Messen der Abdeckung beachten muss. Ein Proof of Concept läuft bereits lokal, technisch ist die Sache also belegt. Die Abstimmung mit den Code-Eigentümern läuft noch.

Zwei Werkzeuge, ein Ziel: den Leuten das Leben leichter machen

Das Unit-Test-Tool ist die eine Seite der Medaille. Die andere ist eine REST-API, über die sich die COBOL-Programme von außerhalb des Mainframes ansprechen lassen.

Ein universeller Dienst übersetzt JSON in den Bytecode, den die COBOL-Programme verarbeiten. Damit wird der Mainframe auch für QS-Leute zugänglich, die keine COBOL-Entwickler sind. Das zählt, denn Mainframe lernt man nicht an der Uni. Die meisten lernen es erst, wenn sie im Unternehmen angefangen haben.

Bartosz fasst die Absicht in einem Satz zusammen: den Leuten das Leben leichter machen. Das Team will COBOL-Entwicklern ein handliches Werkzeug für Unit-Tests geben und zugleich Tester unterstützen, die mit Standardwerkzeugen und ohne Mainframe-Erfahrung kommen.

Tests öffnen die Tür zum Verkleinern des Altsystems

Sind Unit-Tests und funktionale Tests erst einmal da, kann das Team technische Schulden abbauen und die großen COBOL-Programme in kleinere Teile zerlegen.

Das folgt dem Strangler Pattern. Du nimmst das riesige Mainframe-System und schneidest es nach und nach in kleinere Stücke. Das hauseigene Tool soll dabei nicht ewig leben. Füllt irgendwann ein Standardwerkzeug diese Rolle aus, würde das Team gern wechseln.

Einen solchen Ersatz gibt es von IBM bisher nicht. Der ganze Ansatz baut auf dem Standard-Debugger von IBM auf, und kein vergleichbares Werkzeug könnte die Aufgabe übernehmen. Also betreibt das Team seine eigene Brücke weiter und nimmt in Kauf, dass es dafür keinen Herstellersupport gibt.

Das langfristige Ziel bleibt im Blick. Mit Tests im Rücken lassen sich die großen Programme verkleinern und die Altlasten reduzieren. Bis dahin ist es noch weit, aber die Richtung stimmt, und das Management trägt den Weg mit. Für jedes Unternehmen, das mit alten Legacy-Systemen kämpft, ist diese Kombination aus Schnittstelle zu Standardwerkzeugen und Plan zum Verkleinern des Codes der gangbare Weg nach vorn.

Häufig gestellte Fragen

Warum können Standard-Unit-Test-Tools nicht auf stark angepassten Mainframe-Systemen eingesetzt werden?

Standard-Tools setzen Standards voraus. Ein System, das sich schon vor Jahrzehnten von Best Practices verabschiedet hat, besteht aus mehreren Schichten übereinander gestapeltem Eigenentwicklungs-Code, und im beschriebenen Fall konnte das Unternehmen die Standard-Unit-Test-Tools von IBM für COBOL überhaupt nicht nutzen. Eine Anpassung zog die nächste nach sich, bis kein Standardtool mehr an den Code herankam.

Sind technische Schulden in einem Altsystem nur eine Frage von altem Code?

Nein. Der schwierigere Teil ist die Kette von Funktionen, die nie aufgebaut wird. Ohne automatisierte Unit-Tests bricht die Berichterstellung zusammen, die Testabdeckung hat keine Grundlage, und die Validierung einer Änderung vor dem Release wird zum Rätselraten. Die Abhängigkeit verläuft in eine Richtung: Man kann kein Reporting und keine Release-Sicherheit auf eine Testfähigkeit aufbauen, die gar nicht existiert.

Wann ist es sinnvoller, ein eigenes Testtool zu entwickeln, als auf eine Anbieterlösung zu warten?

Wenn der Markt nichts zu bieten hat und die Lücke alles Nachgelagerte blockiert. Da es von IBM kein vergleichbares Tool für diesen Zweck gibt, hat das Team sein eigenes in Java geschrieben und es als Brücke zu Cucumber, Jenkins, Allure, SonarQube und X-Ray behandelt, nicht als weitere verworrene Schicht. Es ist nicht dafür gedacht, ewig zu bestehen: Einen Standard-Ersatz würde das Team gern einsetzen.

Können COBOL-Entwickler realistisch gesehen ihre Tests in einer anderen Sprache schreiben?

Ja, und es kann sogar der einfachere Weg sein. COBOL-Entwickler, die beide Optionen kennengelernt haben, sagten, das Schreiben von Assertions in Java sei einfacher als in COBOL, ihrer Muttersprache. Die API wurde so gestaltet, dass keine Java-Kenntnisse erforderlich sind: Folge den Klammern, füge einen Punkt hinzu, gib einen Variablennamen und einen Wert ein. Die IDE überprüft die Syntax und schlägt Argumente vor.

Warum sind Assertions in COBOL schwieriger zu warten als in Java?

COBOL-Assertions erfordern viel Text und enthalten viel Boilerplate-Code, was den Klartext schwer lesbar und schwer zu warten macht. Java drückt dieselbe Prüfung mit weniger Zeichen aus. Ein kompiliertes COBOL-Programm kann bis zu hunderttausend Zeilen umfassen, während der Java-Test direkt auf die Abschnitte verweist, die als Funktionen dienen, sowie auf die spezifischen Variablen, die geprüft werden.

Lässt sich die Codeabdeckung für COBOL-Programme auf einem Mainframe messen?

Ja, ohne eine eigene Implementierung. Der IBM-Debugger bietet eine Option, die ausgeführte Zeilen erfasst und Statistiken ausgibt. Da jeder Test einen anderen Teil des Programms abdeckt, müssen die Ergebnisse anschließend zusammengefasst werden. Ein Proof-of-Concept läuft bereits lokal; was noch fehlt, ist die Zustimmung der COBOL-Entwickler, denen der Code gehört.

Wie können Tester ohne Mainframe-Erfahrung mit COBOL-Programmen arbeiten?

Über eine REST-API. Ein universeller Dienst übersetzt JSON in den Bytecode, den die COBOL-Programme verarbeiten, sodass QA-Mitarbeiter die Programme von außerhalb des Mainframes mit den Tools steuern können, die sie bereits kennen. Das ist wichtig, weil Mainframe-Kenntnisse nicht an der Uni vermittelt werden: Die meisten lernen sie erst, nachdem sie ins Unternehmen eingetreten sind.

Was ermöglichen Unit-Tests in einem Altsystem über das Aufspüren von Fehlerzuständen hinaus?

Sie ermöglichen es, das System zu verkleinern. Mit Unit- und funktionalen Tests kann ein Team technische Schulden abbauen und die großen COBOL-Programme in kleinere Teile zerlegen: das Strangler Pattern, angewendet auf einen Mainframe. Das Ziel ist noch weit entfernt, aber die Richtung stimmt und die Führungskräfte unterstützen die Bemühungen.

Diese Seite teilen

Ähnliche Beiträge