Automatisiertes Testen einer vertikalen Lösung auf Basis von Dynamics NAV

Motivation

Unsere Software wird stetig weiterentwickelt. Die Entwickler der tegos Group stehen aktuell vor der Herausforderung, dass das manuelle Erzeugen von Testdaten sowie das manuelle Testen der Implementierung sehr aufwändig und zeitintensiv sind. Für jeden neuen Durchlauf des Prozesses muss das Testszenario neu erstellt und ausgeführt werden. Dieser aufwändige Prozess ist sehr fehleranfällig. Eine Automatisierung kann Geld, Zeit und Fehler sparen. Um die Anpassungen an bestehenden und neuen Komponenten während der Entwicklungsphase automatisiert überprüfen zu können, müssen Tests entwickelt werden, die leicht und von jedem ausführbar sind. Dies gewährleistet eine hohe Qualität der Software. Mit diesen automatisierten Tests können Entwickler jederzeit Implementierungen auf ihre korrekte Funktionsweise überprüfen. Ziel ist es, den kompletten Prozess zu automatisieren. Dies beinhaltet die Aktualisierung des Quellcodes, die Erzeugung des ausführbaren Programms und den automatischen Test der Anwendung. Dies nennt man Continuous Integration. Dieser Prozess kann dann zentral in einem festgelegten Zyklus – beispielsweise täglich – ausgeführt werden, um jegliche Änderungen an den Implementierungen zu testen. Wir streben damit kürzere und hochwertigere Auslieferungsintervalle an, um unsere Kunden schneller und einfacher neue Versionen der Software zur Verfügung stellen zu können. Schlägt ein Test fehl, muss ein Entwickler sich umgehend dem Problem annehmen, um eine kontinuierliche Auslieferungsfähigkeit zu gewährleisten. Dies sollte allerdings die Ausnahme sein, da bei allen Änderungen der Software die Tests auszuführen und anzupassen sind.

Die Tests

Es gibt verschiedene Arten von Softwaretests. Der Unit Test (Komponententest) wird auf einer sehr tiefen Ebene des Programmcodes ausgeführt. Hierbei steht ein früher Test im Vordergrund, da Unit Tests direkt nach dem Entstehen der Implementierung entwickelt werden. Im Gegensatz dazu steht der Test Driven Development, bei dem zuerst die Tests und dann die Implementierung entwickelt wird. Unit Tests sollen möglichst nur die kleinsten überprüfbaren Units auf bestimmte Verhalten testen. Gerade bei agilen Methoden zur Softwareentwicklung werden zur Qualitätssicherung häufige Ausführungen der Unit Tests angestrebt. Unit Tests tragen einen erheblichen Beitrag zum Refactoring und zur Sicherstellung der dauerhaften Wiederverwendbarkeit, Erweiterbarkeit und Wartbarkeit bei. Unit Tests helfen auch dabei, das System zu dokumentieren, indem sie beabsichtigte Verwendungen und Reaktionen des Testobjekts deutlich aufzeigen.

Alle Unit Tests werden vor ihrer Entwicklung definiert. Es wird bestimmt, welche Funktionalitäten getestet werden müssen und welche Ergebnisse zu erwarten sind. Funktionen referenzieren oft weitere Komponenten. Diese müssen ebenfalls definiert werden. Ein Beispiel: Ein neues Vertragsmodul soll entwickelt werden. Dazu werden Use Cases definiert. Ein Use Case ist in unserem Fall das Verhandeln eines Vertrags zwischen zwei Händlern. Auf Grundlage dessen wird ein Testszenario definiert. Dieser Test soll prüfen, ob ein Vertrag mit bestimmten Werten angelegt werden kann.

Wir definieren noch einen zweiten Use Case: Die Betragsberechnung. Die Betragsberechnung wird auf Grundlage der im Vertrag angegebenen Menge und des Preises ausgeführt und soll ein bestimmtes Ergebnis zurückliefern. Das bedeutet, dass die Betragsberechnung auf dem Vertrag basiert. Zur Umsetzung bedienen wir uns an den Funktionen aus unserem ersten Test der Vertragserstellung. So wird das Testframework Bottom-Up weiterentwickelt. Zuletzt wird geprüft, ob der tatsächliche Betrag mit dem Erwarteten übereinstimmt. Ist dies nicht der Fall, wird der Test als fehlgeschlagen markiert und der Entwickler muss mit der Fehlersuche beginnen. Der Fehler kann sowohl in der Implementierung als auch im Unit Test selbst liegen.

Bei einem Integrationstest werden laut allgemeingültiger Definition verschiedene Unit Tests zusammengeführt, um das Zusammenspiel verschiedener Komponenten zu testen. Zur Erläuterung dieser Definition erweitern wir das Beispiel des Vertrags und der Betragsberechnung. Wir erstellen einen neuen Unit Test für den Use Case „Verwiegung“. Dabei soll getestet werden, ob ein Gewicht in unserem Waagemodul angegeben und korrekt zurückgegeben werden kann. Die Menge auf dem Vertrag, die zur Berechnung des Betrags benötigt wird, soll vom Waagemodul bereitgestellt werden. Hier werden die drei Unit Tests Vertragsanlage, Betragsberechnung und Verwiegung als Black-Box betrachtet. Diese werden zusammengeführt und auf Integrität geprüft.

Die Grenzen zwischen einem Unit Test und Integrationstest sind fließend. Wir bei der tegos legen auch keinen großen Wert auf eine strikte Trennung. Die automatischen Unit Tests und Integrationstests können einen manuellen Test (User Acceptance Test) leider nicht vollständig ersetzen.

Microsoft stellt für NAV bereits ein „Test Tool Kit“ bereit. Dieses steht zum Testen des Standard NAV-Produkts zur Verfügung. Das bedeutet, dass wir Unit Tests für unsere vertikalen Lösungen auf Grundlage dieser Tests aufbauen und ausführen.

Fazit

Die Bereitstellung von Continuous Integration, Dokumentation, Use Cases und Tests ist eine Grundlage für gute Software Qualität.

Continuous Integration und das damit verbundene kontinuierliche Testen helfen dabei, die Qualität bei fortlaufender Programmierung zu gewährleisten. Die Art der Tests ist zwar nicht allein ausschlaggebend für die Qualität, aber ein wichtiger Faktor. Automatische Tests bedeuten nicht, dass der User-Acceptance-Test wegfällt, sondern nur, dass Funktionen bereits im Vorfeld getestet wurden und dadurch weniger korrigiert werden muss. Eine gute Testabdeckung ist erforderlich, um eine gute Software Qualität zu erzielen. Dabei ist eine komplette Abdeckung des Programmcodes nicht sinnvoll, da dies gerade in umfangreichen Funktionen nahezu unmöglich umzusetzen ist. Es sollte mehr darauf wertgelegt werden, die wichtigsten Teile, wie zum Beispiel die Betragsberechnung in unserem Use Case, abzudecken.

Die Tests sollten anhand der Use Cases definiert werden. Was muss getestet werden? Welche Komponenten müssen gegeben sein? Und welches Ergebnis wird erwartet? Hierbei ist nach Ermessen zwischen dem Unit Test oder dem Integrationstest zu wählen. Bei allen Anpassungen der Software sollen Tests erstellt oder angepasst werden. Die automatisierten Testprozesse sind langfristig kostengünstiger und zuverlässiger als manuelle Testverfahren, da ein Test nur einmal entworfen und programmiert werden muss. Diese Tests können dann ohne nennenswerte Kosten beliebig oft ausgeführt werden.