Du gehst das falsch an. Teste einfach deine Funktionalität: Wenn eine Ausnahme auftritt, schlägt der Test automatisch fehl. Wenn keine Ausnahme auftritt, werden deine Tests alle grün.
Ich habe bemerkt, dass diese Frage von Zeit zu Zeit Interesse weckt, deshalb werde ich etwas ausführlicher darauf eingehen.
Hintergrund zum Unit-Testing
Wenn du Unit-Tests durchführst, ist es wichtig, für dich selbst zu definieren, was du als eine Arbeitseinheit betrachtest. Grundsätzlich handelt es sich um einen Ausschnitt deiner Codebasis, der möglicherweise mehrere Methoden oder Klassen umfasst, die ein einzelnes Stück Funktionalität repräsentieren.
Oder wie in The Art of Unit Testing, 2. Auflage von Roy Osherove, Seite 11, definiert:
Ein Unit-Test ist ein automatisierter Codeabschnitt, der die getestete Arbeitseinheit aufruft und dann einige Annahmen über ein einzelnes Endergebnis dieser Einheit überprüft. Ein Unit-Test wird fast immer unter Verwendung eines Unit-Test-Frameworks geschrieben. Er kann leicht geschrieben und schnell ausgeführt werden. Er ist verlässlich, lesbar und pflegbar. Er ist in seinen Ergebnissen konsistent, solange sich der Produktionscode nicht geändert hat.
Wichtig zu realisieren ist, dass eine Arbeitseinheit in der Regel nicht nur eine Methode ist, sondern auf grundlegender Ebene eine Methode und danach von anderen Arbeitseinheiten verkapselt wird.
Idealerweise sollte für jede separate Arbeitseinheit eine Testmethode vorhanden sein, sodass du sofort sehen kannst, wo etwas schiefgeht. In diesem Beispiel gibt es eine grundlegende Methode namens getUserById()
, die einen Benutzer zurückgibt, und insgesamt 3 Arbeitseinheiten.
Die erste Arbeitseinheit sollte testen, ob ein gültiger Benutzer im Falle von gültiger und ungültiger Eingabe zurückgegeben wird.
Alle Ausnahmen, die von der Datenquelle ausgelöst werden, müssen hier behandelt werden: Wenn kein Benutzer vorhanden ist, sollte ein Test zeigen, dass eine Ausnahme ausgelöst wird, wenn der Benutzer nicht gefunden werden kann. Ein Beispiel hierfür könnte die IllegalArgumentException
sein, die mit der Annotation @Test(expected = IllegalArgumentException.class)
erfasst wird.
Nachdem du alle Anwendungsfälle für diese grundlegende Arbeitseinheit behandelt hast, gehst du eine Ebene höher. Hier machst du dasselbe, behandelst jedoch nur die Ausnahmen, die von der Ebene direkt unter der aktuellen stammen. Auf diese Weise bleibt dein Testcode gut strukturiert und ermöglicht es dir, schnell durch die Architektur zu navigieren, um festzustellen, wo etwas schiefgeht, anstatt wild herumzuspringen.
Behandlung gültiger und fehlerhafter Eingaben von Tests
Jetzt sollte klar sein, wie wir diese Ausnahmen behandeln werden. Es gibt 2 Arten von Eingaben: gültige Eingaben und fehlerhafte Eingaben (die Eingabe ist im strengen Sinne gültig, aber nicht korrekt).
Wenn du mit gültigen Eingaben arbeitest, setzt du die implizite Erwartung, dass jeder Test, den du schreibst, funktionieren wird.
Ein solcher Methodenaufruf könnte so aussehen: existingUserById_ShouldReturn_UserObject
. Wenn diese Methode fehlschlägt (z.B.: eine Ausnahme ausgelöst wird), weißt du, dass etwas schiefgegangen ist und du kannst mit der Fehlersuche beginnen.
Durch das Hinzufügen eines weiteren Tests (nonExistingUserById_ShouldThrow_IllegalArgumentException
), der die fehlerhafte Eingabe verwendet und eine Ausnahme erwartet, kannst du sehen, ob deine Methode tut, was sie mit falscher Eingabe tun soll.
Zusammenfassung
Du hast versucht, zwei Dinge in deinem Test zu überprüfen: gültige und fehlerhafte Eingaben. Indem du dies in zwei Methoden aufteilst, die jeweils eine Sache tun, wirst du viel klarere Tests haben und einen besseren Überblick darüber haben, wo die Fehler auftreten.
Indem du die geschichteten Arbeitseinheiten im Auge behältst, kannst du auch die Anzahl der Tests reduzieren, die du für eine Schicht höher in der Hierarchie benötigst, da du nicht für jedes mögliche Problem in den darunter liegenden Schichten darfst: Die Schichten unterhalb der aktuellen sind eine virtuelle Gewähr dafür, dass deine Abhängigkeiten funktionieren und wenn etwas schief geht, dann liegt es an der aktuellen Schicht (vorausgesetzt, die darunter liegenden Schichten werfen keine Fehler selbst zurück).