Akzeptanztests sind Tests, die als natürlichsprachliche Szenarien aus Anwendersicht formuliert werden. Sie dienen als lebendige Dokumentation eines Systems und können das gemeinsame Verständnis im Team herstellen. Test::BDD::Cucumber
ist eine Distribution, mit der Fehler in Perl-Anwendungen durch die Ausführung von Akzeptanztests gefunden werden können.
In Perl sind Unit-Tests weit verbreitet. Oftmals sind diese als einzige Testart nach außen sichtbar, weil sie in CPAN-Distributionen ausgeliefert werden. Mit der CPAN Testers Matrix gibt es eine transparente Möglichkeit, die Ergebnisse der Unit-Tests einzusehen.
Integrations- oder Systemtests sind bei weitem nicht so bekannt in der Perl-Welt, weil es hierfür weder ein einheitliches Framework noch eine ähnlich transparente Plattform gibt.
Unit-Tests arbeiten »von innen nach außen« (»inside-out«): Die Units bilden die untersten Bausteine, aus denen Anwendungen erstellt werden. Unit-Tests sind gut geeignet für die testgetriebende Entwicklung von Units und üblicherweise schnell in der Ausführung. Deswegen ist es praktisch möglich und ratsam, eine hohe Testabdeckung durch eine Vielzahl von Testfällen zu erreichen.
In der Softwaretechnik gibt es die Disziplin des »behaviour driven development« (BDD), in der Akzeptanztests ein Bestandteil sind.
Diese Art von Systemtests heißt so, weil mit ihnen die Bedingungen geprüft werden, unter denen ein Anwender die Umsetzung der Software akzeptiert. Sie sind natürlichsprachlich aus Sicht des Anwenders formuliert.
Da Anwender in Funktionalitäten denken, werden Akzeptanztests pro Feature geschrieben. Sie bestehen aus Szenarien, die exemplarisch die Verwendung der Software im Rahmen eines Features beschreiben.
Es wird das vollständig integrierte System »von außen nach innen« (»outside-in«) getestet.
Da das vollintegrierte System getestet wird, sind diese Test langsam. Es werden daher nur einzelne bespielhafte Fälle – die Szenarien – getestet.
Akzeptanztests passen gut zu testgetriebener Entwicklung einer Anwendung. In dieser Vorgehensweise spezifiziert man erst das Verhalten der Software aus Sicht des Anwenders in Szenarien und implementiert anschließend das Feature. Die Szenarien helfen beim Konzentrieren auf das Wesentliche eines Features.
Wie sieht nun ein solcher Akzeptanztest aus? Das folgende Beispiel zeigt ein Szenario eines erfolgreichen Logins.
Feature: Login
Scenario: User logs in providing correct credentials
Given I am an existing user
When I log in providing the correct password
Then the login succeeds
And I am at the dashboard page
Szenarien werden nach dem Schema »Arrange, Act, Assert« (AAA) mit der Given-When-Then-Schablone geschrieben. Das Szenario beschreibt aus der Sicht der Benutzers die wesentliche Funktionalität: Nach einem erfolgreichen Login wird der Benutzer auf sein Dashboard geleitet.
Der »Given«-Schritt entspricht »Arrange«, in dem die Voraussetzungen für den Test geschaffen werden. In diesem Fall wird das getestete System so verändert, dass ein Benutzer existiert.
Der »When«-Schritt entspricht »Act«. Hier wird die zu testende Funktionalität ausgeführt.
Im abschließenden »Then«-Schritt (»Assert«) werden die erwarteten Ergebnisse geprüft.
Die Ausführung solcher Szenarien kann in Perl mit einer Reihe von Distributionen erfolgen. Die ausgereifteste ist Test::BDD::Cucumber. Die Akzeptanztests werden standardmäßig im Verzeichnis t/features
abgelegt. Szenarien eines Features werden in einer Datei beschrieben, die auf .feature
endet.
Die einzelnen Schritte werden als Zeichenketten mit regulären Ausdrücken geprüft. Welche dies sind, legen die Entwickler über Subroutinenaufrufe fest. Diese werden in allen Dateien im Verzeichnis t/features/step_definitions
erwartet.
Für unser oben gezeigtes Szenario könnte die Deklaration der einzelnen Schritte wie folgt aussehen:
Given qr{there is an existing user} => sub {
my $context = shift;
# Benutzer anlegen
...
};
When qr{I log in providing the correct password} => sub {
my $context = shift;
# Anmeldung mit korrektem Passwort durchführen
...
};
Then qr{the login succeeds} => sub {
my $context = shift;
# prüfen, ob Login erfolgreich war
...
};
Then qr{I am at the dashboard page} => sub {
my $context = shift;
# prüfen, ob Dashboard angezeigt wird
...
};
Jeder Schritt wird durch diese regulären Ausdrücke geprüft. Bei einer Übereinstimmung wird der entsprechende Code ausgeführt.
Wie im Beispiel zu sehen ist, wird an die Subroutine der Kontext übergeben, in dem der Code ausgeführt wird. Über diesen Kontext können Informationen zwischen den Schritten ausgetauscht werden, ohne auf globale Zustände zugreifen zu müssen. In unserem Beispiel würde hier zum Beispiel der angelegte Benutzer übergeben werden, so dass Name und Passwort nicht fest im Code verdrahtet werden müssen.
Der jeweilige Then-Schritt prüft den erwarteten Zustand mit den aus Test::More
bekannten Werkzeugen.
Die Akzeptanztests werden mit dem Werkzeug pherkin
in der Shell aufgerufen. Bei der Ausführung eines Test werden alle Schritte ausgegeben. Fehler werden laut und deutlich in der Konsole gemeldet:
$ pherkin -Ilib t/features/login.feature
Feature: Login
Scenario: User logs in providing correct credentials
Given I am an existing user
When I log in providing the correct password
Then the login succeeds
step defined at t/features/login.feature line N.
ok - Starting to execute step: the login succeeds
not ok 1
# Failed test at ...
In den »Then«-Schritten können alle Test::Builder
-basierten Testwerkzeuge verwendet werden, die die Entwickler auch sonst in ihren Unit-Tests einsetzen.
Die obigen Beispiele können nur skizzenhaft das Vorgehen zeigen. Die Test::BDD::Cucumber
-Distribution enthält einige lauffähige Beispiele, die konkret die Funktionalität der Distribution zeigen.
Durch das Verwenden von Akzeptanztests ist das Team gezwungen, sich aus der Sicht der Benutzer der Implementierung zu nähern. Dadurch wird häufig deutlich, dass das Wesentliche der Umsetzung einer Software in der Regel nicht in den grafischen Details liegt, sondern vielmehr in der Funktionalität, die der Benutzer erwartet.
Das Team formuliert die Szenarien in einer allgemeinen Sprache (»ubiquitäre Sprache«) der Anwendungsdomäne. Da dieses bereits bekannte Vokabular verwendet wird, kann das gemeinsame Verständnis über die Funktionsweise der Software erhöht werden. Da die Tests zudem ausführbar sind, erhält das Team so eine ausführbare, lebendige Dokumentation des tatsächliche funktionierenden Systems.
Akzeptanztests testen die lauffähige Software mit all ihren Komponenten und nicht nur einzelne Teile. Sie sind daher sehr gut dazu geeignet, um nach Abschluss von Unit- und Integrationstests Fehler in der Zusammenarbeit aller Softwarebausteine einer Anwendung zu finden.
Abschließend führe ich noch einige bewährte Vorgehensweisen auf, um diese Vorteile tatsächlich nutzen zu können.
Das Testen mit Akzeptanztests erfordert im Team einiges Umdenken im Vergleich zum Testen mit Unit-Tests. Es wird aber damit belohnt, dass im Ergebnis eine lebendige und ausführbare Dokumentation des Systems vorliegt. Diese Dokumentation wurde mit einem gemeinsamen Vokabular verfasst, das das gemeinsame Verständnis ermöglicht.
Test::BDD::Cucumber
ist eine Distribution, mit der Akzeptanztests in Perl geschrieben werden können. Die Distribution kann verwendet werden, um nach der erfolgreichen Ausführung von Unit-Tests Fehler im voll integrierten System zu finden.