Während meiner Tätigkeit beim Kunden wird immer wieder die Frage gestellt, was genau eigentlich ein Unit-Test ist. In vielen Fällen gibt es die inoffizielle, interne Definition, dass eine Unit einer Klasse entspricht und man jede Methode einzeln testen muss. Getter- und Setter-Methoden werden häufig von den Tests ausgenommen, wenn sie lediglich für das Abfragen und Setzen von klasseninternen Variablen verwendet werden. Ein Test für eine solche Unit wird meistens mit einer Variante des xUnit-Testframeworks geschrieben und innerhalb eines automatisierten Build-Prozesses ausgeführt.
Wenn man die Frage etwas genauer betrachtet, beinhaltet sie eigentlich 2 verschiedene Aspekte die sich aus den Worten Unit und Test ableiten:
- Was ist eigentlich eine Unit?
- Was macht einen Test für eine solche Unit aus?
Was ist eine Unit?
Der Ausdruck Unit kommt aus dem Englischen und wird im Deutschen gerade im Zusammenhang mit Tests mit Modul bzw. Komponententest übersetzt. Wenn man bei Wikipedia nach der Definition von Modul und Komponente sucht, erhält man folgendes:
Modul:
Ein Modul ist eine abgeschlossene funktionale Einheit einer Software, bestehend aus einer Folge von Verarbeitungsschritten und Datenstrukturen. Aufgabe eines Moduls ist eine Berechnung oder Bearbeitung von Daten, die mehrfach durchgeführt werden muss. Das Modul liefert bei der Rückkehr an das aufrufende Programm Daten als Ergebnis zurück.
Komponente:
Eine Software-Komponente ist ein Software-Element, das konform zu einem Komponentenmodell ist und gemäß einem Composition-Standard ohne Änderungen mit anderen Komponenten verknüpft und ausgeführt werden kann
Eine Komponente zeichnet sich also dadurch aus, dass sie ein Element einer komponentenbasierten Anwendung darstellt und definierte Schnittstellen zur Verbindung mit anderen Komponenten besitzt. Die genaue Form einer Komponente ist abhängig vom jeweiligen Komponentenmodell.
Allerdings muss man beachten, dass die Begrifflichkeit der Unit noch aus einer Zeit stammt, als die imperative Programmierung das vorherrschende Programmierparadigma war. Aus der objektorientierten Sicht ist eine Komponente meines Erachtens nach die Zusammenstellung von mehreren Modulen und würde damit im Rahmen eines Integrations-Tests geprüft werden.
Das Modul ist entsprechend der Definition einer Sammlung von einer oder mehrerer Klassen , die eine funktionale Einheit bilden. Ein Unit-Test ist dementsprechend der Test genau dieser funktionalen Einheit.
Was genau macht nun den Test einer solchen funktionalen Einheit aus?
Der Test soll zeigen, dass die funktionale Einheit entsprechend ihrer Spezifikation arbeitet. Da eine Spezifikation gerade in der agilen Entwicklung meist nur in den Köpfen der Entwickler existiert, die mit Hilfe ihrer funktionalen Einheit eine Funktion der zu erstellenden Anwendung bereitstellen wollen, werden Unit-Tests meistens auch von ihnen codiert. In der Testgetriebenen Entwicklung erfolgt die Implementierung eines solchen Tests, bevor die eigentliche funktionale Einheit geschrieben wird. Daher werden die Tests kontinuierlich während der Entwicklung von dem Entwickler ausgeführt, um so zu testen, ob die Funktionalität bereits erreicht wurde.
Dies heißt auch, dass die Tests so implementiert werden müssen, dass sie alle Aspekte abdecken. Insbesondere sollten für die Eingabewerte eine Aquivalenzklassen- und Grenzwertanalyse durchgeführt werden. Dabei sollte ein Test jeweils nur einen Aspekt testen, damit ein Entwickler aufgrund des Testnamens und der Fehlerausgabe direkt auf das Problem schließen kann. Damit die Laufzeit aller Tests eines Moduls so gering wie möglich ist, sollten alle externen System durch Fake-Implementierungen ersetzt werden.
Um die Funktionalität auch bei späteren Änderungen sicherzustellen, sollten die hier erstellten Unit-Test bei einem automatischen Build immer mitgetestet werden, sobald die zugehörige funktionale Einheit geändert wird.
All diese Aspekte finden sich meines Erachtens nach in der Definition von Roy Osherove für einen Unit-Test und eine Unit wieder:
A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about the behavior of that unit of work.
A unit of work is a single logical functional use case in the system that can be invoked by some public interface (in most cases). A unit of work can span a single method, a whole class or multiple classes working together to achieve one single logical purpose that can be verified.
Zusammenfassend kann man sagen, dass ein Unit-Test die kleinsten funktionalen Einheiten einer Anwendung testet und während eines automatischen Builds immer mitgetestet werden soll. Allerdings darf man nie vergessen, das eine Anwendung die Summe aller kleinen Teile ist und daher das Zusammenspiel mit der Hilfe von Integration-, System- und Akzeptanztest ebenfalls getestet werden muss.
Hi Andrej,
guter Beitrag und ich hab’s kapiert 😉 Ich sende Dir kommende Woche mal ein paar Zeilen zu den Testtools, mit denen ich mich gerade beschäftige.
Beste Grüße und bleib gesund!
Wolfgang
Hallo Wolfgang,
ich bin gespannt. Bleib du ebenfalls gesund in dieser Zeit.
Gruß,
Andrej