Ich habe eine Skelettimplementierung, wie in Punkt 18 von Effective Java (ausführliche Diskussion hier ). Es ist eine abstrakte Klasse, die zwei öffentliche Methoden methodA () und methodB () bereitstellt, die Unterklassenmethoden aufrufen, um "die Lücken zu füllen", die ich nicht abstrahiert definieren kann.
Ich habe es zuerst entwickelt, indem ich eine konkrete Klasse erstellt und Unit-Tests dafür geschrieben habe. Als die zweite Klasse kam, konnte ich allgemeines Verhalten extrahieren, die "fehlenden Lücken" in der zweiten Klasse implementieren und es war fertig (natürlich wurden die Komponententests für die zweite Unterklasse erstellt).
Die Zeit verging und jetzt habe ich 4 Unterklassen, von denen jede 3 kurze geschützte Methoden implementiert, die sehr spezifisch für ihre konkrete Implementierung sind, während die Skelettimplementierung die gesamte generische Arbeit erledigt.
Mein Problem ist, dass ich beim Erstellen einer neuen Implementierung die Tests erneut schreibe:
- Ruft die Unterklasse eine bestimmte erforderliche Methode auf?
- Hat eine bestimmte Methode eine bestimmte Anmerkung?
- Erhalte ich die erwarteten Ergebnisse von Methode A?
- Erhalte ich die erwarteten Ergebnisse von Methode B?
Während sehen Vorteile mit diesem Ansatz:
- Es dokumentiert die Anforderungen der Unterklasse durch Tests
- Bei einem problematischen Refactoring kann dies schnell fehlschlagen
- Testen Sie die Unterklasse als Ganzes und über ihre öffentliche API ("funktioniert methodA ()?" Und nicht "funktioniert diese geschützte Methode?").
Das Problem, das ich habe, ist, dass die Tests für eine neue Unterklasse im Grunde genommen ein Kinderspiel sind: - Die Tests sind in allen Unterklassen alle gleich, sie ändern nur den Rückgabetyp der Methoden (die Skeleton-Implementierung ist generisch) und die Eigenschaften I. Überprüfen Sie den Assert-Teil des Tests. - Normalerweise haben die Unterklassen keine spezifischen Tests für sie
Ich mag die Art und Weise, wie sich die Tests auf das Ergebnis der Unterklasse selbst konzentrieren und es vor Refactoring schützen, aber die Tatsache, dass die Implementierung des Tests nur "manuelle Arbeit" wurde, lässt mich denken, dass ich etwas falsch mache.
Ist dieses Problem beim Testen der Klassenhierarchie häufig? Wie kann ich das vermeiden?
ps: Ich habe darüber nachgedacht, die Skelettklasse zu testen, aber es scheint auch seltsam, ein Modell einer abstrakten Klasse zu erstellen, um sie testen zu können. Und ich denke, dass ein Refactoring der abstrakten Klasse, das das Verhalten ändert, das von der Unterklasse nicht erwartet wird, nicht so schnell bemerkt wird. Mein Mut sagt mir, dass das Testen der Unterklasse "als Ganzes" der bevorzugte Ansatz ist, aber bitte zögern Sie nicht, mir zu sagen, dass ich falsch liege :)
ps2: Ich habe gegoogelt und viele Fragen zu diesem Thema gefunden. Einer von ihnen ist dieser, der eine großartige Antwort von Nigel Thorne hat. Mein Fall wäre seine "Nummer 1". Das wäre großartig, aber ich kann es derzeit nicht umgestalten, also müsste ich mit diesem Problem leben. Wenn ich umgestalten könnte, hätte ich jede Unterklasse als Strategie. Das wäre in Ordnung, aber ich würde immer noch die "Hauptklasse" und die Strategien testen, aber ich würde kein Refactoring bemerken, das die Integration zwischen Hauptklasse und Strategien unterbricht.
ps3: Ich habe einige Antworten gefunden, die besagen, dass es "akzeptabel" ist, die abstrakte Klasse zu testen. Ich bin damit einverstanden, dass dies akzeptabel ist, aber ich würde gerne wissen, welcher Ansatz in diesem Fall der bevorzugte ist (ich beginne immer noch mit Unit-Tests).