Softwareentwicklung: Konzentration auf Unit-Tests greift zu kurz

code-monitor (Bild: Shutterstock)

Testen ist ein wichtiger Bestandteil der agilen Softwareentwicklung. Je später Fehler entdeckt werden, desto aufwändiger und kostenintensiver ist es, sie zu beheben. Für die Umsetzung eines Continuous-Delivery-Prozesses sind daher vollständig automatisierte Tests über den gesamten Entwicklungsprozess hinweg unerlässlich.

Immer kürzer werdende Go-to-Market-Zyklen erfordern permanente Tests über den gesamten Entwicklungsprozess. Automatisierte Test-Routinen entlasten Tester und stellen die Qualität des Produktes sicher. In der Praxis hat es sich bewährt, Anwendungen wiederholt auf drei Ebenen zu überprüfen.

Auf der ersten Ebene geht es darum sicherzustellen, dass sich eine bestimmte Funktion oder Klasse wie erwartet verhält. Entwickler erstellen dazu sogenannte Unit-Tests. Unit-Tests nehmen nur einzelne Einheiten in den Blick. Sie liefern daher keine Hinweise auf mögliche Fehler bei der Zusammenarbeit mehrerer Komponenten.

Christoph Deppisch, einer der beiden Autoren dieses Gastbeitrags für silicon.de, ist Consultant und Software-Architekt bei Consol (Bild: Consol)
Christoph Deppisch, einer der beiden Autoren dieses Gastbeitrags für silicon.de, ist Consultant und Software-Architekt bei ConSol (Bild: Consol)

Die Integrationstests der zweiten Ebene konzentrieren sich auf das Zusammenspiel mehrerer Einheiten und überprüfen dabei das Verhalten mehrerer Code-Module und deren Schnittstellen.

Die sogenannten User-Interface (UI)-Tests gehören der dritten Test-Ebene an. Sie simulieren Benutzeraktionen auf unterschiedlichen grafischen Oberflächen um sicherzustellen, dass die vom Server gelieferten Daten immer korrekt angezeigt werden.

Testautomatisierung verbessert Softwarequalität

Die Automatisierung dieser drei Testarten bekommt eine immer größere Bedeutung. Entwicklungsbegleitende, voll automatisierte Tests stellen kontinuierlich die Release-Fähigkeit der Software fest. Damit kann die Stabilität einer Anwendung viel öfter und vor allem früher im Entwicklungsprozess beurteilt werden, so dass potenzielle Fehler schneller und häufiger erkannt werden.

Tobias Schneck, der zweite Autor dieses Gastbeitrags für silicon.de, ist Software-Consultant bei Consol (Bild: Consol)
Tobias Schneck, der zweite Autor dieses Gastbeitrags für silicon.de, ist Software-Consultant beim Münchner Beratungs- und Softwarehaus ConSol (Bild: Consol)

Allerdings sind die verschiedenen Testarten nicht gleich einfach zu automatisieren. Bei Unit-Tests ist die Automatisierung durch Frameworks wie JUnit etabliert und gilt als Standard in der Softwareentwicklung. Abhängigkeiten werden durch Mocks ersetzt. Dadurch lassen sich die Unit-Tests schnell und einfach ausführen.

Integrations- und UI-Tests dagegen benötigen eine komplexere Infrastruktur. Die Anwendung muss komplett gestartet werden und Abhängigkeiten zu anderen Systemen und Komponenten müssen simuliert werden, um aussagekräftige Ergebnisse zu liefern. Die Vorbereitung der richtigen Infrastruktur hat eine deutlich höhere Komplexität und bedeutet Aufwand. Bei der Überprüfung der Oberfläche kommt zusätzlich noch die Simulation von validen Anwendereingaben hinzu.

Viele Manager scheuen deshalb häufig die Kosten für das Einführen einer vollständigen Testautomatisierung in den Bereichen Integrations- und UI-Tests. Mit den richtigen Tools bleibt aber auch diese Investition im Rahmen, so dass sich kontinuierliche, vollautomatische Tests mittel- und langfristig immer lohnen.

Die Releasefähigkeit einer Anwendung kann durch Testautomatisierung kostengünstig und schnell überprüft werden und ist Voraussetzung für eine zeitgemäße Time-to-Market-Strategie. Manuelle Tests sind dann nur noch ausgewählten Fachanwendern vorbehalten, die sich vor einem Release ganz gezielt auf die neuen Funktionen einer Anwendung konzentrieren, um die Übereinstimmung mit den Anforderungen zu prüfen und fachliche Fehler auszuschließen.

Testautomatisierung vereinfacht die Fehlersuche

Unternehmen sollten in Entwicklungsprojekten bereits von Anfang an eine Automatisierung vorsehen. Dabei müssen alle drei Testarten fester Bestandteil des Build-Prozesses sein, damit sie bei jeder Änderung automatisch ausgeführt werden. Bei der Einbindung in die Build-Umgebung gilt das Prinzip des Failfast-Ansatzes, bei dem ein Fehlschlag dazu führt, dass die weiteren Prozess-Schritte nicht mehr ausgeführt werden.

Die Infrastruktur einer vollständigen Testumgebung für den Integrations-Test kann sehr aufwändig sein. Ein mögliches Setup im Überblick. (Grafik: Consol)
Die Infrastruktur einer vollständigen Testumgebung für den Integrations-Test kann sehr aufwändig sein. Ein mögliches Setup im Überblick. (Grafik: Consol)

Die Anzahl der Tests und die Vielfalt der Varianten, die getestet werden, nehmen mit jeder Testebene von unten nach oben immer weiter ab. Basis dieser Hierarchie sind die schnell ausführbaren Unit-Tests, die sehr nah am Quellcode arbeiten und dabei viele Varianten sowie möglichst alle Entscheidungswege prüfen. Danach verschiebt sich der Fokus auf ausgewählte Tests von Komponenten und Schnittstellen. Auf der letzten Ebene wird gezielt die Anwendererfahrung ausgewertet und das Gesamtsystem kommt in den Blick.

Die sinkende Anzahl der Testvariationen in den oberen Testhierarchieebenen sorgt für eine größere Effizienz des gesamten Entwicklungsprozesses. Wegen des größeren Aufwands und der deutlich längeren Ausführungszeit der Tests im Bereich Integration und UI wird der Durchlauf auf die wesentlichen Prüfroutinen beschränkt.

PartnerZone

Effektive Meeting-und Kollaboration-Lösungen

Mitarbeiter sind heute mit Konnektivität, Mobilität und Video aufgewachsen oder vertraut. Sie nutzen die dazu erforderlichen Technologien privat und auch für die Arbeit bereits jetzt intensiv. Nun gilt es, diese Technologien und ihre Möglichkeiten in Unternehmen strategisch einzusetzen.

Eine wichtige Randbedingung erfolgreicher Testautomatisierung ist die Organisation der Projektteams. Die Erfahrung zeigt, dass cross-funktionale Teams, die alle Bereiche wie Test, Softwareentwicklung und Releasemanagement behandeln, die beste Lösung sind. Bessere Kommunikation und Zusammenarbeit sowie eine gleichmäßigere Wissensverteilung unter den Mitarbeitern sind die Folge. Kurze Wege und regelmäßiger Austausch vermeiden zeitintensive Kommunikationsschleifen zwischen Bug-Eröffnung, Test-Verifizierung und Bug-Behebung. Daher ist es beim Beginn des Projekts empfehlenswert, eine gemeinsame Arbeitsgrundlage mit einem einheitlichen Vorgehensmodell wie Scrum oder Kanban sowohl für die Entwicklung als auch das Testen zu finden.

Sichtbarkeit der Tests im Team

Eine besonders kritische Situation im Entwicklungsprozess entsteht, wenn über Stunden oder Tage im Continuous Build mehrere Fehler auflaufen und sich überlagern. Dadurch kann niemand nachvollziehen, welcher Fehler zu welcher Code-Änderung gehört. Dies erschwert die Fehlerbehebung unnötig und muss unbedingt verhindert werden. Wenn das Entwicklerteam nicht auf Stabilität achtet, gewöhnen sich rasch alle an einen fehlerhaften Build und es sinkt zunehmend die Bereitschaft, die Fehler zu beseitigen. Nach kurzer Zeit ist dann keine korrekte Aussage über die Qualität der Software mehr möglich. Dieser Zustand verhindert das Deployment oder führt zu unerkannten Fehlern im Produktivsystem.

Stationen auf dem Weg zum Continuous Deployment (Grafik: Consol)
Stationen auf dem Weg zum Continuous Deployment (Grafik: Consol)

Eine gute Lösung ist es, in der täglichen Teambesprechung Fehler im Continuous Build in Listenform zusammenzutragen und anschließend in eine Rangfolge zu bringen. Dies erhöht für das Team die Sichtbarkeit der Tests und der Zuständigkeiten für einen fehlgeschlagenen Build. Um die Qualität dauerhaft hoch zu halten, sollte die Feedback-Schleife des Builds kurzfristig alle notwendigen Daten zur Fehleranalyse liefern. Der Test-Code sollte Gegenstand eines Reviews sein, um die Einhaltung von Guidelines dauerhaft sicherzustellen. Ein empfehlenswertes und den Gesamtablauf entlastendes Verfahren ist eine Vereinbarung im Team, vor dem Check-in des Quellcodes Unit- und ausgewählte Integrations-Tests lokal auszuführen, um offensichtliche Fehler schon vorab zu bemerken.

Continuous Deployment als nächste Stufe der Automatisierung

Die Testautomatisierung ist nur der erste Schritt einer Continuous-Delivery-Pipeline. Nach den Tests folgt das automatisierte Deployment der Anwendung zum Beispiel in Form eines Java-Web-Archivs in einem Application Server. Das Artefakt wird automatisiert durch den Build erstellt, getestet und in ein Repository (zum Beispiel Maven, Docker) abgelegt.

In diesem Zusammenhang bedeutet Automatisierung, dass nach dem Commit des Entwicklers keine manuellen Aktionen notwendig sind, um das fertige Artefakt zu erhalten. Tools wie Jenkins besitzen alle notwendigen Funktionen, um eine solche Continuous Integration (CI) Pipeline aufzusetzen. Der nächste Schritt ist dann Continuous Delivery. Hier wird die CI-Pipeline um ein automatisiertes Deployment erweitert, das ein beliebiges Zielsystem mit einem Klick aktualisiert.

Ausgewähltes Whitepaper

Studie zu Filesharing im Unternehmen: Kollaboration im sicheren und skalierbaren Umfeld

Im Rahmen der von techconsult im Auftrag von ownCloud und IBM durchgeführten Studie wurde das Filesharing in deutschen Unternehmen ab 500 Mitarbeitern im Kontext organisatorischer, technischer und sicherheitsrelevanter Aspekte untersucht, um gegenwärtige Zustände, Bedürfnisse und Optimierungspotentiale aufzuzeigen. Jetzt herunterladen!

In diesem Zusammenhang können verschiedene manuelle Genehmigungsschritte eingebaut sein. Denkbar ist, dass ein Testmanager Systeme für die Abnahme mit einem einzigen Klick bereitstellen kann. Für das Deployment der Produktivumgebung hingegen könnte nur ein bestimmtes Betriebsteam die Berechtigung haben. Sobald diese automatischen Prozesse fehlerfrei ablaufen und einen hohen Reifegrad erreicht haben, kann als nächster Schritt zur vollständigen Automatisierung das Continuous Deployment eingeführt werden. Der Auslöser für die Bereitstellung der Produktivumgebung ist hier entweder der Commit eines Entwicklers oder ein Zeitintervall – zum Beispiel nachts um 3 Uhr.

Nicht jeder Automatisierungsgrad ist für alle Projekte sinnvoll, organisatorische Rahmenbedingungen müssen bei der Entscheidung berücksichtigt werden. Unternehmen sollten aber auf jeden Fall ein automatisiertes Deployment anstreben. Damit kann sich das Projektteam auf die Kernaufgabe der Anwendungsentwicklung konzentrieren. Die manuelle Bereitstellung von Test- und Produktivsystemen lenkt von der Hauptsache ab, ist im Nachhinein schwer nachvollziehbar und nicht wiederholbar, meist schlecht dokumentiert und somit nicht effizient genug.

Fazit

Die vollständige Automatisierung der Unit-, Integrations- und UI-Tests ist eine Grundvoraussetzung für Continuous Delivery in der Softwareentwicklung. Die Überprüfung der Anwendungsintegration und Benutzerschnittstellen ist schwieriger zu automatisieren und benötigt spezielle Vorbereitungen bezüglich Infrastruktur und Testdaten. Durch den Einsatz spezialisierter Tools lässt sich dieser Aufwand beherrschen und die Automatisierung wird eine mächtige Waffe im Kampf gegen Bugs.

Automatisierte Tests ermöglichen schnelle und häufige Lieferungen einer Software und sind bei einem zukünftigen Refactoring wertvoll. Der erhöhte Testaufwand zahlt sich damit bei jeder Lieferung und jedem frühzeitig entdeckten Fehler doppelt aus. Schnelle Feedback-Zyklen und definierte organisatorische Zuständigkeiten sind nicht zuletzt auf dem Weg zu einem erfolgreichen Continuous-Deployment-Prozess unverzichtbar.