Einer der größten Vorteile beim Schreiben von automatisierten Tests ist es, per Knopfdruck verschiedene Testfälle zu berücksichtigen.
Damit eine Software möglichst stabil ist, muss man jedoch so viele Fehlerfälle berücksichtigen, wie es nur geht. Der Kreativität sind hierbei keine Grenzen gesetzt.
Dabei unterscheidet man grundsätzlich zwischen einem edge case, corner case und einem best case (happy path).
Edge case
Mit einem edge case (Grenzfall, Sonderfall) verhindert man bereits viele Fehler. Diese äußern sich in vielen Fällen in einer Art Validierungslogik. Der Test könnte in etwa so aussehen:
[Test]
public void StreetMustNotContainOnlyNumbers()
{
var address = new Address("14001", "12a", 14001, "Potsdamm");
var validator = new AddressValidator();
var result = validator.Validate(address);
Assert.That(result.IsValid, Is.False);
}
Es kann durchaus passieren, dass der Benutzer (un)bewusst falsche Eingaben in der Maske tätigt und dadurch invalide Daten erzeugt.
Hierbei sollte man direkt ein Gegentest schreiben, der überprüft, ob Zahlen überhaupt noch erlaubt sind:
[Test]
public void StreetCanContainNumbers()
{
var address = new Address("B3rl1ner Str.", "12a", 14001, "Potsdamm");
var validator = new AddressValidator();
var result = validator.Validate(address);
Assert.That(result.IsValid, Is.True);
}
Und natürlich, ob ganz normale Straßennamen noch unterstützt werden:
[Test]
public void PropperStreetNamesMustBeSupported()
{
var address = new Address("Berliner Str.", "12a", 14001, "Potsdamm");
var validator = new AddressValidator();
var result = validator.Validate(address);
Assert.That(result.IsValid, Is.True);
}
Aber auch ganz absurde Testfälle sollte man an der Stelle berücksichtigen
[Test]
public void MoreThanOneSpecialCharsMustNotBeSupported()
{
var address = new Address(" ¯\_(ツ)_/¯ ", "12a", 14001, "Potsdamm");
var validator = new AddressValidator();
var result = validator.Validate(address);
Assert.That(result.IsValid, Is.False);
}
Adressen können in der Tat essenziell sein. Beispielsweise, wenn der Kunde in einem Onlineshop einkauft und aus Versehen eine invalide Adresse eingibt. Dies kann ggf. gravierende, geschäftsrelevante Folgen haben.
Und ich glaube, das möchtest du deinem Kunden nicht erklären wollen, oder?
Corner case
Eine weitere Art von Testfällen sind die Corner cases. Diese sind in einigen Fällen etwas schwierig (aber nicht unmöglich) zu formulieren.
Kurz gesagt, sind es Fälle, die normalerweise gar nicht auftreten können. Diese könnte beispielsweise durch diverse Folgefehler entstehen oder auch durch die Verkettung mehrerer Prozesse, die unabhängig voneinander korrekt funktionieren, in Kombination jedoch ein Fehler auslösen.
Der einfachste corner case, den man eigentlich immer berücksichtigen muss, ist die Prüfung auf z.B. null oder auch ein Leerstring etc. Also alles, was bereits in der GUI oder in der Datenquelle verboten wurde oder auch vorher „wegvalidiert“ wurde.
In vielen aktuellen Onlineshops kann man ja bereits im Voraus per z.B. PayPal, Amazon, Klarna oder der klassischen Kreditkarte bezahlen.
Ich persönlich finde das ja mega praktisch und nutze das sehr gerne. So laufe ich nicht in die Gefahr, zusätzliche Mahngebühren zahlen zu müssen, weil ich vergessen habe, die Rechnung zu bezahlen.
Aber was passiert eigentlich, wenn just in dem Augenblick, nachdem der Kunde bezahlt hat und der Auftragsbestätigung die Internetverbindung abbricht? Sowohl das Geld, als auch die Bestellung wären dann weg.
Ein anderer, gar nicht mal so unrealistischer Fall wäre es, wenn der Datenbankserver während des Anlegens der Bestellung ein Timeout hat und der Kunde sich wundert, warum seine Waren nach 2 Wochen immer noch nicht da ist.
Eine kleine Änderung an einer API kann ebenfalls gravierende Folgen für deine laufende Anwendung haben. Häufig ist es so, dass hier noch nicht einmal Tests anspringen, weil die API in den Tests lediglich simuliert wird.
Warum man das machen sollte, habe ich ja bereits hier beschrieben.
Die hier skizzierten Testfälle sind nur einige, die mir so spontan eingefallen sind. Bestimmt werden dir noch viele mehr einfallen, wenn du mal so an deine Anwendung denkst.
Auch hier gilt: Deiner Kreativität sind keine Grenzen gesetzt. Jeden Fehler, den du hier lokalisierst und gar nicht erst zulässt, wird dir langfristig sehr viel Geld sparen!
Best case / Happy path
Die (in meinen Augen) langweiligste, aber auch wichtigste Form von Tests, sind die happy paths. Das sind die Testfälle, die unter realen Bedingungen funktionieren müssen.
Und bevor die Frage aufkommt, es gibt hierzu kein exakt definiertes Gegenteil. Am verbreitetsten ist der unhappy path. Ich mag aber auch die Bezeichnung sad paths.
Eine kleine Geschichte hierzu: Ich war vor einiger Zeit in einem lokalen Einrichtungshaus und habe mir Möbel bestellt. Als meine Adresse aufgenommen wurde, wollte das System meine korrekte(!!!) Adresse nicht akzeptieren, weil es angeblich die Straße nicht gäbe. Schlussendlich hat es sich herausgestellt, dass „Straße“ ein eigenständiges Wort sein muss und so etwas wie „Poststr.“ oder „Poststraße“ nicht erlaubt sind.
Dabei wären die Tests hierfür ziemlich einfach gewesen.
[TestCase("Poststr.")]
[TestCase("Poststraße")]
[TestCase("Post Straße")]
[TestCase("Post Str.")]
public void CommonAbbreviationsMustBeAccepted(string streetName)
{
var address = new Address(streetName, "12a", 14001, "Potsdamm");
var validator = new AddressValidator();
var result = validator.Validate(address);
Assert.That(result.IsValid, Is.True);
}
Das „TestCase“-Attribut ist NUnit spezifisch. Da es aber eine Portierung von jUnit ist, sollten es auch jUnit, PHPUnit etc. auch unterstützen. Falls nicht, spricht auch nichts dagegen, hierfür mehrere Tests zu schreiben.
Grundsätzlich sind es solche Tests, die wir normalerweise durch die UI testen und die Daten wie z.B. „asd“ oder „qwe“ erzeugen. Gibt zu, du kennst solche Datensätze 😉
Fazit – Testsfälle
Fassen wir kurz zusammen: Eine stabile Software muss viele einzelne Fälle berücksichtigen. Es darf sich nicht nur korrekte Daten (Happy paths) verlassen werden, sondern muss auch immer auf Fehler reagieren können (Sad path).
Diese Art von Tests dürfen in keiner Anwendung Fehler:
- Tests mit sehr großen oder sehr kleinen Eingabewerten
- Tests mit unerwarteten Eingabewerten oder Eingabemustern
- Tests mit unvollständigen oder ungültigen Eingabedaten
- Tests mit fehlerhaften oder beschädigten Daten
Aber eins steht jedoch fest. Selbst wenn du sehr viele Tests hast, heißt es nicht gleichzeitig, dass deine Software komplett fehlerfrei ist. Schließlich kannst du ja auch nicht an alles denken.
Und da gibt es auch noch die Softwaretester, die dir so einiges um die Ohren hauen werden. Diese Ergebnisse formulierst du wiederum als Test und schon seid Ihr beide glücklich.
Wie bist du eigentlich auf deinem Tester zu sprechen, wenn er ein Bug findet? Freust du dich oder ärgert dich das eher? Schreib es gerne in die Kommentare!