Sind Sie als Tester oder Testmanager in einem agilen Projekt unterwegs? Sprechen Sie mit „Ihren Entwicklern“ darüber, welche Testfälle diese automatisiert haben? Und passen Sie Ihre Tests darauf hin an? Ändern Sie etwas an Ihren Tests, wenn die Testautomation im Projektverlauf nicht mehr gepflegt wird?
Testautomation im agilen Umfeld
In der Schweiz werden rund die Hälfte der IT-Projekte mit agilen Methoden umgesetzt (siehe SwissQ Agile Trends und Benchmark, https://www.swissq.it/agile-de/research-information/). Die hohe Anzahl an durchzuführenden Sprints stellt besondere Anforderungen an das Test-Team. In jedem neuen Sprint steigt die Anzahl an Regressionstestfälle und diese wachsende Flut an Tests erfordert einen hohen Grad an Testautomation (https://de.wikipedia.org/wiki/Agiles_Testen).
Martin Fowler, einer der Vordenker in diesem Umfeld, spricht dabei von der Test Pyramide und plädiert dafür, dass die Testbasis von der Entwicklung in Form von Unit Test erfolgen soll.
(Quelle: https://martinfowler.com/bliki/TestPyramid.html)
In der Praxis sehe ich sehr unterschiedliche Abdeckungsraten von Code durch Testautomation der Entwickler. Unabhängig vom Abdeckungsgrad ersparen die Unit Tests uns „normalen Testern“ aber nicht die Durchführung von System- oder Abnahmetests. Neben der eigentlichen Businesslogik, die heutzutage in der Service-Schicht implementiert wird, sind an der Oberfläche weitere Validierungen zu prüfen. Zudem sind in der Systemtestphase auch nichtfunktionale Dinge wie Usability, Mehrsprachigkeit und Design zu testen.
Ein Tester mit iPhone und Android Geräten bei der Durchführung von Tests
Gute Entwicklerteams führen zwar viele automatische Unit-Tests durch, aber sind das die richtigen Tests? Meist werden die Tests ja eben nicht von ausgebildeten, erfahrenen Testern erstellt. Grosses Verbesserungspotential liegt hier brach. Weder kann der Tester seine Fähigkeiten in die Testautomation einbringen, noch kann er davon profitieren, dass ein Teil der notwendigen Tests bereits automatisiert durchgeführt wird. Letztlich ignoriert er die TA wenn sie durchläuft – und schimpft evtl. gar, wenn die Tests mal wieder rot sind.
Tester sind häufig nicht technisch genug, um selbst die Testautomation durchzuführen. Entwickler sind meist nicht ausgebildet für die systematische Erstellung von Testfällen. Und was ist mit den Business Analysten und dem Fachbereich? Die Spezialisten für fachliche Spezialfälle, bekommen die Testfälle schon gar nicht zu sehen und können somit nicht ihr Fachwissen mit einbringen.
Geht das nicht besser?
Eine mögliche Lösung, kann die Trennung von Testcode und Testdaten sein. Dies kann mit Keyword Driven Testing (https://de.wikipedia.org/wiki/Keyword_driven_testing) und Datengetriebenem Testen (Datadriven Testing (https://en.wikipedia.org/wiki/Data-driven_testing) erfolgen. Gute Werkzeuge zur Testautomation unterstützen es z.B. Variablen in CSV-Dateien auszulagern und dort zu pflegen. Dadurch umfasst der Testcode viel weniger Umfang, ist sogar einfacher strukturiert und ist dadurch auch einfacher zu warten.
In der Theorie sollten die Testdaten in diesem Vorgehen sogar vom Fachbereich erstellt werden. Selbst wenn man das organisatorisch hinbekommt, so ist dies jedoch nicht ohne Probleme. Nicht nur haben wir wieder die Situation, dass nicht ausgebildete Personen für die Erstellung der Tests zuständig sind, auch führt der Ansatz dazu, dass diverse Excel-Files rumgemailt werden, auf irgendwelchen Netzlaufwerken liegen – und auch schon mal verloren gehen oder die falsche Version benutzt wird. Das sollte mit etwas Selbstdisziplin und Selbstorganisation in den Griff zu bekommen sein, erweist sich in der Praxis aber nur selten als erfolgreich.
Zusammengefasst liegen die Probleme also in den Bereichen:
- Entwickler, Tester und Fachbereich reden nicht über die automatisierten Tests. Dies führt zu Mehrfachdurchführung oder Lücken in der Abdeckung
- Wenn Testcode und Testdaten verschmelzen, dann ist der Testcode aufwendig zu erstellen und zu warten
- Datengetriebene Testautomation erlaubt die Auslagerung der Testdaten in Excel Dateien. Es ist aber oft unklar, wie diese verwaltet werden können
Datengetriebene Testautomation mit FitNesse
Das Open Source Framework FitNesse (https://fitnesse.org) verspricht nun Lösungen für die oben angesprochenen Probleme. Es ist, vereinfacht gesagt, ein Wiki, dass um Testautomationsfunktionen erweitert wurde. Der grosse Vorteil an diesem Ansatz ist die extrem hohe Flexibilität, bei gleichzeitig automatischer Disziplin im Sinne von
- Testdaten/Testfälle werden auf der gleichen Seite wie die Anforderungen/Dokumentation erfasst. Dadurch entfallen Mails, Filesysteme, etc.
- Jeder kann die Tests verstehen, ausführen und korrigieren. Dadurch haben Tester, Entwickler UND Fachbereich eine gemeinsame Basis um über Tests zu sprechen
- Man kann automatische und manuelle Testfälle mischen und behält so den Überblick darüber, wer was testet
- Da FitNesse ein Wiki Server ist, kann die Ausführung von beliebigen Usern über beliebige Zugangspunkte erfolgen
- Es gibt umfangreiche REST-Schnittstellen für die Integration in andere Werkzeuge oder das Monitoring des Betriebs
- Da alles textbasiert ist, kann eine effiziente Integration in die eingesetzte Versionsverwaltung erfolgen
Ein paar Beispiele sollen die Probleme traditioneller Tests verdeutlichen und aufzeigen, wie diese mit FitNesse gelöst werden können. FitNesse unterstützt alle gängigen Programmiersprachen, die Beispiele in diesem Artikel sind in Java gehalten.
Beispiel Sparplan
Als Beispiel soll eine Android App dienen, die unter anderem einen Sparplan berechnen kann. Die Tests hierfür können grob in GUI-Spezifische Tests (Bedienung, Usability, Geräte-Kompatiblität, etc.) und Tests der Berechnung eingeteilt werden.
Dabei ist offensichtlich, dass die Bedienung auf dem Gerät langsam und damit teuer ist. Gleichzeitig ist die Automation auf GUI-Ebene aufwendig und benötigt spezielle Werkzeuge. Viel einfacher erscheint es bei solchen Fällen, die Automation direkt auf dem Code anzusetzen. Idealerweise ist dies aber nicht dem Entwickler aufzubürden, sondern durch einen Testspezialisten zu erledigen.
Hier zunächst das Beispiel eine JUnit-Tests, wie er für die Berechnung erstellt worden sein könnte
Wenn die Methode folgende Signatur hat:
public static double calculateAccumulatedValue
(double start, double rates, double interest, int years) {}
Könnte ein typischer Test wie folgt aussehen:
@Test
<b>public</b> <b>void</b> testCalculateAccumulatedValue() {
assertEquals(110.0, InterestCalculator.calculateAccumulatedValue(100, 0, 10, 1), 0.1);
assertEquals(100.0, InterestCalculator.calculateAccumulatedValue(100, 0, 0, 1), 0.1);
assertEquals(110.0, InterestCalculator.calculateAccumulatedValue(100, 10, 0, 1), 0.1);
assertEquals(0.0, InterestCalculator.calculateAccumulatedValue(0, 0, 0, 0), 0.1);
}
Wie unschwer zu erkennen ist, fehlt dem Testfall die Lesbarkeit. Auch ist keine Systematik in der Erstellung zu erkennen und er ist längst nicht ausreichend im Umfang. Weder der typische manuelle Tester noch der Business Analyst kann diesen Testfall ohne viel Mühe verstehen.
Ein manueller Tester würde sich wohl ein Excel erstellen, ein paar Fälle durchrechnen und diese dann eingeben. Das Excel bleibt dabei hoffentlich für künftige Tests erhalten...
Die Lösung mit Hilfe von FitNesse gestaltet sich nun wie folgt. Die Testfälle werden in Form einer Tabelle direkt in das Wiki eingetragen und können per Knopfdruck ausgeführt werden. Wie man sehen kann, sind die Tabellen von Menschen lesbar und so können alle Projektbeteiligten leicht über die Details sprechen, eigene Testfälle ergänzen oder eben selbst einmal auf den Test-Knopf drücken. Wer Berührungsängste hat: Es gibt natürlich einen Excel Import/Export...
Der eigentliche Testcode muss dabei weiterhin von den Entwicklern erstellt werden. Sie können sich aber darauf konzentrieren, was sie am besten können: Entwickeln. Um Testfälle und Testdaten kümmern wir Tester uns künftig.
Unschwer ist zu erkennen, dass die Testfälle (noch immer nicht vollständig) systematisch ermittelt wurden, aufgrund der Tabellenstruktur und des Kommentars leicht verständlich sind und ein fehlgeschlagener Test klar markiert ist. Mit solchen Mitteln ist es einfach, den Fachbereich dazu zu bringen, selbst ein paar Beispiele beizusteuern.
Und der Code für die Testautomation? Der Java Code hinter diesem Beispiel ist sehr einfach, da er eben keine Testdaten enthält. Im Grunde hat man nur noch einfache Get- und Set-Methoden und einen Aufruf der zu testenden Funktion. Wie angedeutet wird der Code dadurch sehr einfach zu erstellen und zu warten. Das FitNesse Framework kümmert sich darum, die Aufrufe und Rückgaben zu steuern.
public class InterestCalculatorTests
{ public InterestCalculatorTests() {}
int years;
double start, rates, interest;
public void setYears(int years)
{this.years = years;}
public void setStart(double start) {this.start = start;}
public void setRates(double rates) {this.rates = rates;}
public void setInterest(double interest)
{this.interest = interest;}
public double result() { return InterestCalculator.calculateAccumulatedValue(start, rates, interest, years);}
public void setComment(String txt){ System.out.println(txt); }
}
Fazit und Zusammenfassung
Der Artikel hat einige der Probleme aufgezeigt, die Testautomation im agilen Umfeld haben kann. An einem Beispiel wurde aufgezeigt, wie Testautomation mittels Datengetriebener Testautomation einfacher erstellt, verwaltet und dokumentiert werden kann. Diese Art der Testautomation eignet sich besonders für Non-GUI-Tests. Für GUI Workflows ist der Schlüsselwortgetriebene Ansatz besser geeignet. Der grosse Vorteil von FitNesse ist, dass beide Ansätze unterstützt werden.