Ich schrieb einen Testfall für eine Methode mit folgender Signatur:
Ich bestückte die Methode mit einem HashSet und 2 Elementen. Nun hatte ich eine bestimmte Vorstellung, wie diese Methode arbeitet:
Gebe die Elemente innerhalb der Collection durch Komma getrennt aus.
Ich bin aber darauf reingefallen, dass HashSet natürlich die Einfügereihenfolge nicht betrachetet. Der Testfall schlug einmal fehl, einmal lief er durch, weil ich im Test nicht die beiden möglichen Ergebnisse berücksichtigte. Ein Kollege meinte, dass die Ausgabe natürlich abhängig ist von der Art der Collection, die übergeben wird und der nachfolgende Aufrufer auch keine Zusicherung der Reihenfolge benötigt.
Ich persönlich finde Methoden, die zufällig ein Element eines Ergebnisraums liefern, etwas seltsam. Deshalb hätte ich in jedem Fall das Ziel verfolgt, das Ergebnis des Rückgabewertes nicht abhängig zu machen vom Typ der konkreten Implementierung einer Collection, die der Aufrufer übergibt, unabhängig davon, ob der Aufrufer mit jedem Element des Ergebnisraumes zurechtkommt. Ich stelle mir da insbesondere die Fehlersuche und das Testen schwerer vor, zumal mit zunehmer Komplexität der Ergebnisraum stetig zunimmt.
Erster Gedanke: Unter der Voraussetzung, dass mir die Reihenfolge egal ist, was sie definitiv ist, würde ich intern den Typ X total ordnen, sodass das Ergebnis meiner Methode, egal in welcher Reihenfolge die Elemente aus der Collection kommen, immer gleich ist.
Zweiter Gedanke: Auch wenn mir die Reihenfolge egal ist, könnte ich die den Parameter weiter konkretisieren und dem Aufrufer zwingen, etwas zu übergeben wo er sich über die Ordnung der Elemente Gedanken machen muss (z.B. SortedSet).
Dritter Gedanke: Auch wenn mir die Reihenfolge egal ist, könnte ich den Parameter weiter konkretisieren und dem Aufrufer eine Abstraktionsstufe anbieten, wo er sich über die Reihenfolge Gedanken machen kann, aber nicht muss (Einfügereihenfolge, LinkedHashSet). Der Aufrufer hätte die Option, dass Ergebnis nach seinen Wünschen zu gestalten, oder er lässt es halt bleiben. In jedem Fall wäre für ihn das Verhalten manchmal vielleicht egal aber immer klar nachzuvollziehen. Nachteil wäre, dass man sich auf eine konkrete Implementierung festlegt, die aber aus meiner Sicht vollständige Transparenz und Nachvollziehbarkeit garantiert.
Vierter Gedanke: Einfach nur das Verhalten der Methode dokumentieren und beim Testen mit allen Ergebnissen aus dem Ergebnisraum rechnen.
Zusatzinformationen:
Das o.g. Beispiel ist eine Vereinfachung der Struktur, mit der ich es zu tun habe. Im Endeffekt wird objektorientiert versucht eine HQL-Abfrage aufzubauen (ähnlich der Criteria-Abfragen von Hibernate). Ich lasse mir als Tester der API den HQL-String geben, und der sieht halt jedesmal anders aus, wenn ich ein HashSet für bestimmte Definitionen verwende. Setzte man das HQL tatsächlich ab, würde man zwar jedes mal das gleiche Ergebnis bekommen, aber ich würde gerne isoliert den Aufbau des Query-Strings testen und nicht Hibernate, Hibernate-Mapping, Netzwerk, Datenbank und/oder Tabellenschema. Deshalb war die Idee, dass ich mir den HQL-String nach dem Aufbau der Query geben lasse und gegen den Erwartungswert vergleiche.
Beispiel:
Erwartungswert:
select o1 from DummyClassA o1 left join fetch o1.childrenBImpl o2 left join fetch o2.childrenCImpl o3 left join fetch o2.childrenDImpl o4
Tatsächlich:
select o1 from DummyClassA o1 left join fetch o1.childrenBImpl o2 left join fetch o2.childrenDImpl o3 left join fetch o2.childrenCImpl o4
Ich bin nicht ganz sicher, was man anstreben sollte. Über Anregungen würde ich mich freuen.
Java:
String buildString(Collection<X> collection)
Gebe die Elemente innerhalb der Collection durch Komma getrennt aus.
Ich bin aber darauf reingefallen, dass HashSet natürlich die Einfügereihenfolge nicht betrachetet. Der Testfall schlug einmal fehl, einmal lief er durch, weil ich im Test nicht die beiden möglichen Ergebnisse berücksichtigte. Ein Kollege meinte, dass die Ausgabe natürlich abhängig ist von der Art der Collection, die übergeben wird und der nachfolgende Aufrufer auch keine Zusicherung der Reihenfolge benötigt.
Ich persönlich finde Methoden, die zufällig ein Element eines Ergebnisraums liefern, etwas seltsam. Deshalb hätte ich in jedem Fall das Ziel verfolgt, das Ergebnis des Rückgabewertes nicht abhängig zu machen vom Typ der konkreten Implementierung einer Collection, die der Aufrufer übergibt, unabhängig davon, ob der Aufrufer mit jedem Element des Ergebnisraumes zurechtkommt. Ich stelle mir da insbesondere die Fehlersuche und das Testen schwerer vor, zumal mit zunehmer Komplexität der Ergebnisraum stetig zunimmt.
Erster Gedanke: Unter der Voraussetzung, dass mir die Reihenfolge egal ist, was sie definitiv ist, würde ich intern den Typ X total ordnen, sodass das Ergebnis meiner Methode, egal in welcher Reihenfolge die Elemente aus der Collection kommen, immer gleich ist.
Zweiter Gedanke: Auch wenn mir die Reihenfolge egal ist, könnte ich die den Parameter weiter konkretisieren und dem Aufrufer zwingen, etwas zu übergeben wo er sich über die Ordnung der Elemente Gedanken machen muss (z.B. SortedSet).
Dritter Gedanke: Auch wenn mir die Reihenfolge egal ist, könnte ich den Parameter weiter konkretisieren und dem Aufrufer eine Abstraktionsstufe anbieten, wo er sich über die Reihenfolge Gedanken machen kann, aber nicht muss (Einfügereihenfolge, LinkedHashSet). Der Aufrufer hätte die Option, dass Ergebnis nach seinen Wünschen zu gestalten, oder er lässt es halt bleiben. In jedem Fall wäre für ihn das Verhalten manchmal vielleicht egal aber immer klar nachzuvollziehen. Nachteil wäre, dass man sich auf eine konkrete Implementierung festlegt, die aber aus meiner Sicht vollständige Transparenz und Nachvollziehbarkeit garantiert.
Vierter Gedanke: Einfach nur das Verhalten der Methode dokumentieren und beim Testen mit allen Ergebnissen aus dem Ergebnisraum rechnen.
Zusatzinformationen:
Das o.g. Beispiel ist eine Vereinfachung der Struktur, mit der ich es zu tun habe. Im Endeffekt wird objektorientiert versucht eine HQL-Abfrage aufzubauen (ähnlich der Criteria-Abfragen von Hibernate). Ich lasse mir als Tester der API den HQL-String geben, und der sieht halt jedesmal anders aus, wenn ich ein HashSet für bestimmte Definitionen verwende. Setzte man das HQL tatsächlich ab, würde man zwar jedes mal das gleiche Ergebnis bekommen, aber ich würde gerne isoliert den Aufbau des Query-Strings testen und nicht Hibernate, Hibernate-Mapping, Netzwerk, Datenbank und/oder Tabellenschema. Deshalb war die Idee, dass ich mir den HQL-String nach dem Aufbau der Query geben lasse und gegen den Erwartungswert vergleiche.
Beispiel:
Erwartungswert:
select o1 from DummyClassA o1 left join fetch o1.childrenBImpl o2 left join fetch o2.childrenCImpl o3 left join fetch o2.childrenDImpl o4
Tatsächlich:
select o1 from DummyClassA o1 left join fetch o1.childrenBImpl o2 left join fetch o2.childrenDImpl o3 left join fetch o2.childrenCImpl o4
Ich bin nicht ganz sicher, was man anstreben sollte. Über Anregungen würde ich mich freuen.