Für was schreibt man Unit-Tests?

Die Anforderungen sind sehr abstrakt und allgemein.
Das reicht noch nicht für eine Implementierung.

Bei den Collections hat sich ja auch keiner gedacht: "Ich will eine Lagerverwaltung implementieren", sondern "Ich definiere ein Interface zur allgemeinen Speicherung von Daten, für das es verschiedene Implementierungen geben kann
Doch, ich denke schon dass es so ähnlich war. Anforderung: eindeutig Key/Value Paare speichern. Welche Methoden sind sinnvoll? Dann definiert man sinnvolle Implementierungen (HashMap, SynchronizedHashMap, ...). Dann definiert man, dass konkrete Implementierungen von diesem Verhalten abweichen können. Die Bedingungen sind am Interface erläutert. Das bedeutet, dass das Interface nicht das Verhalten wiederspiegeln muss, nur eine Schnittstelle für Zugriffe. Andere Sachen aber werden festgelegt (eben z.B. key/value Paare ohne Duplikate in den Keys).

Map (Java Platform SE 6)

Und genau um letzteres zu prüfen, reicht es IMHO nicht, in allen Implementierungen einrach "nachzusehen"....
Wieso nachsehen?. Man schreibt Tests gegen konkrete Implementierungen (sprich der Entwickler der Klasse) und deren Verhalten.

Definiert eine Methode als Rückgabewert Map und liefert eine bestimmte Implementierung, die u.U. nicht alle Funktionalitäten bietet, die man erwarten würde, dann ist das m.E. ein Fehler. Das gilt natürlich nicht, wenn das zu erwartende Verhalten dokumentiert ist.

Java:
Map getNotExtendableButModifyableData();

Wäre also ok (Außer evtl. die Namensgebung ;-) )
Da würde ich dann testen können, ob der Vertrag eingehalten wird.

Java:
NotExtendableButModifyableMap getTheMap();
Ist auch ok. Hier muss ich nicht noch testen, ob die Map das Verhalten einhält. Ich gehe davon aus, dass das passiert ist.
 
Das reicht noch nicht für eine Implementierung.
...
Anforderung: eindeutig Key/Value Paare speichern. Welche Methoden sind sinnvoll?

Ich meinte damit, dass die Anforderungen auf einer tieferen, technischen Ebene beschrieben sind - eigentlich "kurz davor", automatisch geprüft werden zu können: Statt einem Kommentar "[c]returns never null[/c] gibt's teilweise schon Annotations wie [c]@NeverNull[/c], die (fast ähnlich zu Eiffel Conditions) bis zu einem gewissen Grad automatisch (also noch autmatischer als Unit-Tests) überprüft werden können.

Die Möglichkeit, in der JavaDoc ggf. ein Verhalten zu beschreiben, das von dem abweicht, das man von dem zurückgegebenen Objekt eigentlich erwartet werden würde, ändert nichts daran, dass man in einem "tiefen" Unit-Test dann ja eigentlich wieder genau dieses Verhalten abprüfen müßte. Und das IST einfach aufwändig :bahnhof:
 
geht es nun darum ob man Zusicherungen im Code per Javadoc garantieren soll ?! Ich kenne nahezu keine JavaDoc die mit dem aktuellsten Stand der Implementierung einhergeht ;-).

Es ist wohl ein unterschied ob irgendwo etwas textlich dokumentiert ist oder ob es Systeme gibt, die eben dieses auch programmatisch ueberpruefen.

Und wenn du die Wahl hast zwischen JavaDoc oder UnitTest (da beides ja aufwaendig ist) -> immer UnitTest 😀
 
Ich meinte damit, dass die Anforderungen auf einer tieferen, technischen Ebene beschrieben sind - eigentlich "kurz davor", automatisch geprüft werden zu können: Statt einem Kommentar "[c]returns never null[/c] gibt's teilweise schon Annotations wie [c]@NeverNull[/c], die (fast ähnlich zu Eiffel Conditions) bis zu einem gewissen Grad automatisch (also noch autmatischer als Unit-Tests) überprüft werden können.
Ja, dann brauche ich natürlich keinen expliziten Test für die Prüfung auf ungleich null. Ähnlich könnte es sich auch mit Java-Asserts verhalten (sofern die VM während der Tests mit asserts enabled läuft).

Die Möglichkeit, in der JavaDoc ggf. ein Verhalten zu beschreiben, das von dem abweicht, das man von dem zurückgegebenen Objekt eigentlich erwartet werden würde, ändert nichts daran, dass man in einem "tiefen" Unit-Test dann ja eigentlich wieder genau dieses Verhalten abprüfen müßte. Und das IST einfach aufwändig :bahnhof:
Das ist richtig und auch gut so. Denn (z.B. das Interface Map) verbirgt nicht nur die Implementierung, sondern auch das Verhalten. Somit muss es für diese Anforderung explizit überprüft werden.

Was mache ich, wenn ich das nicht möchte, aber trotzdem die Implementierung dahinter verbergen möchte? Dann sollte ich ein eigenes Interface schreiben, dass u.U. von Map ableitet und genau dieses Verhalten beschreibt. Die Implementierung kann dann dieses Interface implementieren und wird für sich getestet. Wird dieses Interface von einer Methode zurückgeliefert, brauche ich es nicht mehr testen.

Und ja, saubere Tests schreiben ist aufwendig und langwierig. Ich verbringe sicher viel Zeit mit dem Schreiben von Tests. Mit Tests für konkrete Bugs dann evtl. sogar noch mehr. Aber ich habe auch gemerkt, dass wesentlich weniger Fehler gemeldet werden und vor allem die Wartung der Software wesentlich weniger zeitintensiv ist. Das rechnet sich schnell.
 
@bygones: JavaDocs sind für manche Dinge eben die einzig "portable" Möglichkeit. Die Versuche, dem mit Annotations entgegen zu wirken gehen sicher in die richtige Richtung, sind aber bisher nur erste Schritte.

Und ja, saubere Tests schreiben ist aufwendig und langwierig. Ich verbringe sicher viel Zeit mit dem Schreiben von Tests. Mit Tests für konkrete Bugs dann evtl. sogar noch mehr. Aber ich habe auch gemerkt, dass wesentlich weniger Fehler gemeldet werden und vor allem die Wartung der Software wesentlich weniger zeitintensiv ist. Das rechnet sich schnell.

Die Vorteile und das "für was" von Unit-Tests (im zum Threadtitel komplementären Sinn) sind mir schon klar. Und dass man diese Vorteile nicht umsonst bekommt auch. Aber nachdem ich in dem Guava Map-Test den Aufwand gesehen habe, der betrieben werden muss, um es richtig zu machen, erscheint mir das aus den hier im Thread ausführlich besprochenen Gründen kaum praktikabel. So bleibt also nur, dass man versucht, im Pareto-Sinn die 80% (nicht Testabdeckung 😉 ) zu erreichen...
 

Zurück
Oben