Warum brauch ich Tests?

Bauen Sie Software die stabil, durchdacht und fehlerfrei ist? Hatten Sie noch nie ein Bug oder ein falsches Verhalten in Ihrer Software?

GLÜCKWUNSCH, Sie sind wohl der einzige Softwareentwickler, dem dieser Zaubertrick gelingt.

Die Realität sieht leider oft so aus, dass wir immer wieder feststellen, dass etwas nicht richtig funktioniert. Die Gründe können hier sehr vielfältig sein, eine falsche Annahme, eine Änderung an der Schnittstelle oder viele andere Gründe.

Die Grundregel ist, je früher wir einen Fehler finden, desto weniger kostet es uns diesen zu beheben. Ist ein Fehler erst einmal Live müssen wir viel mehr für die Reparatur investieren, als wir es in der Entwicklungsphase müssten.

Tests sollen uns also helfen Fehler früh zu erkennen und die Qualität der Software zu verbessern.

Die Vielfalt der Tests:

Es gibt verschiedene Arten von Tests, daher stellt sich auch die Frage welcher Test hat welche Funktion? Nachfolgend möchte ich die gängigsten Tests einmal auflisten und erläutern.

Unit Tests

Der vermutlich am meisten genutzten Test, aber auch oft nicht ganz korrekt umgesetzte Test, ist der Unit Test. Das Wort Unit, Einheit, ist hier wichtig, denn ein solcher Test sollte nur seine Einheit testen. Als Einheit wird hier meistens eine Methode aber maximal die Klasse gesehen.

Oft sehe ich, dass ein Test die Eingabe über eine Schnittstelle, die Verarbeitung der Daten in mehreren Klassen und die Ausgabe testet. So ein Test testet also mehrere Einheiten und ist somit kein Unit Test.

In einem Unit Test testen wir zum Beispiel eine Methode, welche eine Liste sortiert oder einen Filter auf einen Text anwendet, aber nicht die Eingabe oder Darstellung.
Werden andere Klassen oder Methoden benötigt, werden diese durch sogenannte Mocks ersetzt und liefern den erwarteten Wert zurück, den wir in unserem Test definieren.

Weitere Infos zur Definition von Unit Tests

Integration Tests

Bei Integration Tests handelt es sich um die zweite Art von Tests, die sehr häufig verwendet werden.

Wie der Name schon sagt, testen wir hier eine Integration, also das Zusammenspiel mehrerer Komponenten. Dies sind Tests die tatsächlich auch Operationen auf Datenbanken oder das Zusammenspiel mehrerer Services miteinander Testen.

Bei Integration Tests sollten im Normalfall auch keine Mocks verwendet werden. Den durch das Verwenden von Mocks, teste ich immer eine Annahme. Sollte sich also die Datenbank Struktur ändern würde ich dies durch einen Mock nicht bemerken und teste am Ende auch nicht die Integration dieser, sondern meine Annahme.

Weitere Infos zur Definition von Integration Tests

Functional Tests

Die Abgrenzung von Funktionalen Tests zu Integration Tests ist etwas dünner. Das Prinzip ist sehr ähnlich auch hier testen wir mehrere Komponenten.

Während ich beim Integration Tests vor allem teste ob die Anbindung funktioniert, ist ein Funktionaler Test darauf ausgelegt das Ergebnis zu prüfen.

Ein Beispiel, während der Integration Test nur prüft ob ich eine Abfrage auf der Datenbank vornehmen kann, prüft der Funktionale Test ob die Datenbank auch genau das erwartete Ergebnis, auf die Abfrage zurück liefert.

End-to-end Tests

Ein Ende zu Ende Test geht hier noch weiter als ein Funktionaler Tests.

Hier wird in einer vollständigen Systemumgebung, das Benutzer Verhalten getestet. Dies kann ein einfacher Login sein, aber auch die Registrierung mit einer E-Mail Bestätigung.

Das Automatisieren solcher Tests ist meistens nicht sehr einfach, da zum Beispiel im Falle einer versendeten E-Mai mit Link nicht nur die eigene Applikation getestet werden muss, sondern auch das Postfach geöffnet, die richtige E-Mail ausgewählt werden und der Link geöffnet werden muss.

Acceptance Tests

Diese Tests finden ebenfalls in einer vollständigen Systemumgebung statt. Akzeptanz Tests sind vor allem da um Kriterien zu testen, welche durch Anforderungen definiert wurden.

Hier kann es sich um Performance Tests, wie zum Beispiel bekommt der Benutzer eine Benachrichtigung in der vorgeschriebenen Zeit, handeln.
Es können aber auch Funktionale Tests sein, wie der Kunde muss nach einem 5. falschen Login gesperrt werden.

Performance Tests

Diese Art von Tests prüft keine Funktionalität wie Integration oder Funktionale Tests, hier geht es um Stabilität und Geschwindigkeit der Anwendung.

Es sollen vor allem Fragen beantwortet werden wie, wie viele User können sich gleichzeitig einloggen, was passiert, wenn ein User große Daten sendet wie funktioniert das Load Balancing.

Diese Tests sind oft sehr kostspielig und haben vor allem das Ziel Kennzahlen für den Betrieb der Anwendung zu liefern.

Smoke Tests

Diese Art von Tests ist die simpelste Art von Integration Test die gemacht werden kann.

Wurden früher Rohre verlegt, hat man am Ende Rauch in die Rohre geblasen und geschaut wo dieser austritt. Heute sendet man eher ein Request von einem Service zum anderen und schaut nur ob dieser ankommt.

Smoke Tests sind einfache Tests, die Grundlagen testen um nach Änderungen zu schauen ob man überhaupt alle anderen Tests ausführen kann. Schlägt ein Smoke Test fehl, kann diese zum Beispiel bedeuten, dass die Datenbank nicht erreichbar ist, somit muss ich keine Integration gegen diese testen.

Weitere Infos zur Definiton von Smoke Tests

Regression Tests

Diese Art von Tests entspricht meistens einem Unit Test, kann aber auch ein Integration Test sein.

Sein Zweck ist es Regression zu vermeiden, dies bedeutet, sollte ich einen Bug beheben schreibe ich einen Test, der genau diesen Bug testet. Durch diese Art von Tests soll verhindert werden, dass wir den gleichen Fehler mehrfach beheben müssen.

Wann Teste ich?

Die wohl wichtigste Frage ist wann teste ich überhaupt, gleichzeitig ist es die einfachste Frage, IMMER!

Ist eine Software nicht getestet bin ich wie ein Pilot im Sturm, ohne Instrumente und fliege durch Nebel, der mir die Sicht nimmt. Wenn ich Glück habe und nach Links fliege komme ich vielleicht weiter, aber es kann genauso sein, dass dort ein Berg im Weg ist.
Ohne Tests kann ich nicht prüfen welche Auswirkung meine Änderungen am Code haben und ob noch alles funktioniert.

Es gibt nicht ohne Grund auch eine Methode die sich “Testgetriebene Entwicklung“ nennt. Man muss diesem Paradigma nicht unbedingt folgen, aber Tests sollten immer geschrieben werden.

Welche Tests brauche ich?

Den Anfang machen die Unit und Integration Tests. Währen eigentlich jede Methode mit einem Unit Test abgedeckt werden kann, werden die Integration Tests doch erst benötigt, wenn mehrere Komponenten zusammenspielen.

Funktionale Tests kommen dann meist auch mit den Integration Tests hinzu.

Bei allen anderen Tests kommt es immer auch auf die Anforderungen an die Software an. Wie groß ist die Anwendung, was muss getestet sein, ist Performance und Ausfallsicherheit wichtig?

Die Testabdeckung:

Was ist Testabdeckung?

Testabdeckung beschreibt im Allgemeinen wieviel vom Code durch einen Unit Test oder Integration Test abgedeckt wird.

Das Problem mit dieser Kennzahl ist, dass die Abdeckung keinerlei Hinweis auf die Qualität des Tests gibt. Es können also auch Tests dazu zählen welche eine Methode aufrufen aber am Ende nur prüfen ob “true == true” richtig ist. Normalerweise sollte man aber davon ausgehen, dass ein Entwickler auch einen sinnvollen Test schreibt.

Somit kann die Testabdeckung durchaus einen Einblick über die Qualität der Software geben, da eine gut getestete Software meistens auch eine gute Software ist.

Wie viel Testabdeckung ist sinnvoll?

Hier ist zu allererst zu sagen 100% sollten nie das Ziel sein. In Java ist es sogar ein eigentlich nicht zu erreichendes Ziel.

Warum aber nun keine 100% oder 99%? Haben Sie schon mal erlebt, dass ein simpler Getter oder Setter, der wirklich nur das Feld übergibt etwas falsch macht?
Es macht also kaum Sinn für einen solchen Fall einen Test zu schreiben.

Unter 50% sollten es aber auch auf keinen Fall sein, dass würde uns keine Sicherheit geben.

Für mich gelten alle Anwendungen die über 80% erreichen als sehr gut getestet, zwischen 80%-60% kann man damit arbeiten, alles unter 60% ist in meinen Augen nur mit den Worten von Admiral Ackbar zu beschreiben, “It’s a trap!”.

Der Code hat Tests, aber sehr große Teile sind nicht abgedeckt, dort lauern nicht vorhersehbare Gefahren.