• IT-Karriere:
  • Services:

Das 0. Gesetz des Testens: Nur die Paranoiden überleben

"Wenn es nicht getestet wurde, funktioniert es nicht." Selbst wenn dieser Satz nicht immer stimmt, ist er sicherlich eine gute Arbeitsgrundlage für die Projektarbeit. Diese Regel bildet jedenfalls die Grundlage für die meisten anderen hier aufgeführten Lektionen.

Stellenmarkt
  1. con terra GmbH, Münster
  2. Stadt Lingen (Ems), Lingen (Ems)

Eine Warnung vorab: Die Welt der möglichen Eingaben und selten auftretenden Sonderfälle ist unendlich. Daher werden Sie mit empirischen Tests niemals eine hundertprozentige Abdeckung erreichen. Sie werden dieses Ziel nie erreichen. Wenn Sie jemals denken, dass Sie mit dem Testen "fertig" sind, werden Sie eine Überraschung erleben. Alles, was Sie tun können ist, so viel Abdeckung zu erreichen, wie es mit der verfügbaren Zeit und den verfügbaren Ressourcen möglich ist.

Manuelles Testen ist nicht gut genug

Dinge, die ich Entwickler sagen höre:

"Das hier ist so wichtig, dass wir es manuell testen müssen. Ich traue einem automatisierten Test diese Aufgabe nicht zu."

"Denken Sie nicht darüber nach, automatisierte Tests zu erstellen. Wir haben diese Änderungen schon manuell getestet."

Ein Hardwareentwickler würde hingegen sagen:

"Das ist so wichtig, dass wir eine automatisierte Testsuite dafür bauen müssen. Ich traue den menschlichen Testern das nicht zu."

"Führen Sie ein paar Tests von Hand durch, als letzte Plausibilitätsprüfung. Verbringen Sie aber nicht zu viel Zeit damit, es wurde ja schon ziemlich gut automatisch getestet."

Ein paar Tests von Hand durchzuführen und die Ergebnisse durchzusehen, mag in einer VLSI-Vorlesung an der Uni funktionieren. Aber in der Industrie wird man Sie dafür auslachen. Manuelles Testen kann nicht auf Github Code-reviewt werden. Manuelles Testen unterliegt menschlichen Fehlern, sei es aus Nachlässigkeit oder Faulheit. Manuelles Testen ist extrem zeit- und arbeitsintensiv, wenn es bei jedem einzelnen Release gemacht wird.

Es mag Ausnahmen geben, bei denen ein Test nicht automatisiert werden kann. Aber es sollten eben Ausnahmen sein - nicht die Regel. Zuverlässigkeit ergibt sich letztlich aus der Stärke der automatisierten Testsuite und nicht daraus, wie viele manuelle Tests gemacht werden. Alles, was wichtig genug ist, um es von Hand zu testen, ist auch wichtig genug, um eine automatisierte Testsuite dafür zu erstellen.

Zwei Eingaben für sich zu testen != sie zusammen zu testen

Angenommen, Ihr Team implementiert und testet die folgende Methode:

  1. public static double myCustomDivider(double numerator, double divisor);

Alice: "Haben wir Tests, die das korrekte Verhalten bei negativen Eingaben überprüfen?"

Bob: "Ich habe einen Test, bei dem der Zähler negativ ist und einen weiteren Test, bei dem der Nenner negativ ist."

Alice: "Hast du einen dritten Test, bei dem beide negativ sind?"

Bob: "Nein, den brauchen wir auch nicht. Wir haben bereits beide Fälle einzeln behandelt."

Lachen Sie ruhig, aber ich habe solche Sätze schon sehr oft gehört, von vielen Senior-Entwicklern.

Wenn die Eingaben vollständig voneinander entkoppelt sind, mag es sinnvoll sein anzunehmen, dass sie nicht in Kombination getestet werden müssen. Aber oft sind zwei Eingaben, von denen man annimmt, dass sie entkoppelt sind, gar nicht so entkoppelt, wie man denkt.

Und selbst wenn die Implementierung zum Zeitpunkt des Schreibens eines Tests tatsächlich entkoppelt ist, kann sie sich zu einem späteren Zeitpunkt zu einer gekoppelten Implementierung entwickeln. Es ist wie in diesem Sprichwort: "Nicht das, was du nicht weißt, bringt dich in Schwierigkeiten, sondern das, was du sicher zu wissen glaubst, obwohl es gar nicht wahr ist."

Als allgemeine Heuristik könnte man sagen: Wenn zwei Eingaben innerhalb derselben Methode geparst werden, ist es definitiv sinnvoll, sie in Kombination zu testen.

Vielleicht haben Sie sich entschieden, dass es das Verhältnis von Risiko und Nutzen rechtfertigt, keine Tests für solche Kombinationen zu schreiben. Das kann durchaus eine vernünftige Entscheidung sein, abhängig von den jeweiligen Projektumständen. Aber seien Sie sich des Risikos bewusst, das Sie damit eingehen. Machen Sie sich nicht vor, es habe keinen Wert, Kombinationen von mehreren Ereignissen zu testen.

Test der Ausgabe_A für Ereignis_1 != Test des Ausgabe_A für Ereignis_2

Angenommen, Sie müssen die folgende addPerson-Methode testen:

  1. public int getAge(String name);
  2. public int getHeight(String name);
  3. public int getWeight(String name);
  4.  
  5. // Returns true if a previous value was overwritten
  6. public boolean addPerson(Person person);

Sie schreiben die folgenden Tests:

  1. @Test
  2. public void addNewPerson_shouldReturnFalse() {
  3. Person person = new Person("john", 30, 175, 70);
  4. boolean result = system.addPerson(person);
  5. Truth.assertThat(result).isFalse();
  6. getAndCheckPerson(person);
  7. }
  8.  
  9. @Test
  10. public void addPerson_alreadyExists_shouldReturnTrue() {
  11. Person originalJohn = new Person("john", 30, 175, 70);
  12. system.addPerson(originalJohn);
  13.  
  14. Person updatedJohn = new Person("john", 31, 174, 71);
  15. boolean result = system.addPerson(updatedJohn);
  16.  
  17. Truth.assertThat(result).isTrue();
  18. getAndCheckPerson(updatedJohn);
  19. }
  20.  
  21. private void getAndCheckPerson(Person person) {
  22. Truth.assertThat(system.getAge(person.name))
  23. .isEqualTo(person.age);
  24. Truth.assertThat(system.getHeight(person.name))
  25. .isEqualTo(person.height);
  26. Truth.assertThat(system.getWeight(person.name))
  27. .isEqualTo(person.weight);
  28. }

Daraufhin kommt es zu folgendem Gespräch:

John: "Hey, warum prüfst du beim zweiten Test Alter/Größe/Gewicht noch einmal?"

Sie: "Warum nicht?"

John: "Wir haben bereits im ersten Test überprüft, ob Alter/Größe/Gewicht korrekt eingegeben wurden. Die einzige inkrementelle Änderung, die im zweiten Test geprüft werden muss, ist die Rückgabe des Booleschen Wertes. Sie können die anderen Prüfungen löschen."

Sie können sich selbst mit verschiedenen logischen Argumenten davon überzeugen, dass es unmöglich ist, dass die zusätzlichen Prüfungen im zweiten Test fehlschlagen, wenn der erste Test bestanden wurde - und diese zusätzlichen Prüfungen deshalb nicht nötig sind. "Ich habe mir den Code angesehen, und wir prüfen nicht einmal, ob die Person existiert, bevor wir sie blindlings einfügen und überschreiben, was schon da ist!"

Handbuch für Softwareentwickler: Das Standardwerk für professionelles Software Engineering

Der ganze Sinn des Schreibens automatisierter Tests ist, (potenziell fehlerhafte) Annahmen zu minimieren. Es geht darum, Sicherheitsnetze einzurichten für den Fall, dass später jemand beschließt, diesen Code umzuschreiben, den Sie überprüft und zu dem Sie mündlich eine Garantieerklärung abgegeben haben.

Abhängig von der spezifischen Implementierung, den Prioritäten Ihres Projekts und dem Aufwand, der mit der Durchführung der Checks verbunden ist, kann es ein vertretbares Risiko sein, sie zu überspringen. Machen Sie sich jedoch nicht vor, dass es kein Risiko gibt. Nur weil etwas für ein Ereignis gut funktioniert, heißt das nicht, dass es auch für alle anderen Ereignisse gut funktioniert. Wenn eine einzeilige Hilfsmethode hilft, solche Annahmen zu vermeiden, gibt es wenig Gründe, sie nicht zu verwenden.

Testen Sie jeden erdenklichen Sonderfall

Mir war nie bewusst, wie paranoid ich bin, bis ich mich dabei ertappte, wie ich immer wieder Gespräche wie dieses führte:

  1. @Test
  2. public void removeElementFromCollection() {
  3. var collection = MyCustomCollection.of(1);
  4. collection.remove(1);
  5. Truth.assertThat(collection).isEmpty();
  6. }

"Woher weißt du, dass die Methode nicht die gesamte Sammlung löscht, statt nur das eine Element zu entfernen?"

  1. @Test
  2. public void removeElementFromCollection_otherElementsRemaining() {
  3. var collection = MyCustomCollection.of(1, 2);
  4. collection.remove(1);
  5. Truth.assertThat(collection).contains(2);
  6. }

"Woher weißt du, dass die Methode nicht einfach jedes Mal das 1. Element rauszieht?"

  1. @Test
  2. public void removeElementFromCollection_lastElementRemoved() {
  3. var collection = MyCustomCollection.of(1, 2);
  4. collection.remove(2);
  5. Truth.assertThat(collection).contains(1);
  6. }

"Woher weißt du, dass das in Fällen, in denen du das mittlere Element entfernen willst, gut funktioniert?"

All das mag pingelig erscheinen, aber es ist der Grad an Paranoia, der nötig ist, um eine sichere Testsuite zu bauen. Eine, die den Release-Prozess gegen eine Vielzahl von Bugs und durch Codeänderungen hervorgerufene Fehler absichern kann. Eine, bei der Sie sich wohlfühlen, wenn die Anwendung nach dem erfolgreichen Durchlauf des Tests ausgerollt wird (deploy-on-success) - und zwar egal, wie tiefgreifend die Änderungen sind.

Wenn eine Methode eine ganze Sammlung von Elementen zurückgibt, schreiben Sie nicht nur Tests, die eine Ausgabe mit einem einzigen Element erzeugen. Schreiben Sie Tests, von denen erwartet wird, dass sie eine ganze Reihe von Ausgaben produzieren, und überprüfen Sie dann, ob jedes einzelne davon auftaucht.

Schreiben Sie Tests, von denen erwartet wird, dass sie überhaupt keine Ausgaben erzeugen. Jede einzelne Prüfung mag trivial und unbedeutend erscheinen, aber in der Summe ergeben sie einen Sinn. Testen Sie jeden Sonderfall, den Sie sich vorstellen können.

Bitte aktivieren Sie Javascript.
Oder nutzen Sie das Golem-pur-Angebot
und lesen Golem.de
  • ohne Werbung
  • mit ausgeschaltetem Javascript
  • mit RSS-Volltext-Feed
 Software-Tests neu denken: Perspektiven aus der Welt der HardwareWhite-Box-Tests zur Verbesserung der Testabdeckung 
  1.  
  2. 1
  3. 2
  4. 3
  5. 4
  6. 5
  7.  


Anzeige
Spiele-Angebote
  1. 79,99€ (Release 10. Juni)
  2. 3,50€
  3. 26,99€
  4. (u. a. Yu-Gi-Oh! Legacy of the Duelist für 7,20€, Yu-Gi-Oh! ARC-V: ARC League Championship für...

xUser 20. Feb 2021 / Themenstart

UI Tests sind prinzipbedingt langsam. Außerdem sind ihre Failures eher unspezifisch zum...

NoGoodNicks 13. Feb 2021 / Themenstart

Korrekt. Und wenn es nicht der Tester ist, dann ist es der Integrator. Der braucht immer...

freebyte 09. Feb 2021 / Themenstart

Dann muss sich in den letzten Monaten etwas geändert haben, was ich nicht mitbekommen...

Steffo 09. Feb 2021 / Themenstart

Kann mich dem nur anschließen. Ich teste auch ziemlich ausführlich und bin für jeden...

Netzweltler 09. Feb 2021 / Themenstart

Daher wird man auch in Zukunft Tests der Software so weit wie möglich beschränken. Daher...

Kommentieren


Folgen Sie uns
       


Mafia (2002) - Golem retro_

Wer in der Mafia hoch hinaus will, muss loyal sein - ansonsten verstößt ihn die Familie. In Golem retro_ haben wir das erneut selbst erlebt.

Mafia (2002) - Golem retro_ Video aufrufen
    •  /