Ich verwende einen ähnlichen Ansatz wie Jon, aber anstatt nur für die aktuelle Zeit Clock
eine spezielle Schnittstelle zu erstellen (z. B. ), erstelle ich normalerweise eine spezielle Testschnittstelle (z. B. MockupFactory
). Ich habe dort alle Methoden angegeben, die ich zum Testen des Codes benötige. In einem meiner Projekte habe ich dort beispielsweise vier Methoden:
- eine, die einen Modelldatenbank-Client zurückgibt;
- eine, die ein Mock-up-Notifier-Objekt erstellt, das den Code über Änderungen in der Datenbank benachrichtigt;
- eine, die ein Modell java.util.Timer erstellt, das die Aufgaben ausführt, wenn ich es möchte;
- eine, die die aktuelle Zeit zurückgibt.
Die getestete Klasse verfügt über einen Konstruktor, der diese Schnittstelle unter anderem akzeptiert. Die ohne dieses Argument erstellt nur eine Standardinstanz dieser Schnittstelle, die "im wirklichen Leben" funktioniert. Sowohl die Schnittstelle als auch der Konstruktor sind paketprivat, sodass die Test-API nicht außerhalb des Pakets ausläuft.
Wenn ich mehr nachgeahmte Objekte benötige, füge ich dieser Schnittstelle einfach eine Methode hinzu und implementiere sie sowohl in Test- als auch in realen Implementierungen.
Auf diese Weise entwerfe ich Code, der in erster Linie zum Testen geeignet ist, ohne dem Code selbst zu viel aufzuerlegen. Tatsächlich wird der Code auf diese Weise noch sauberer, da viel Fabrikcode an einem Ort gesammelt wird. Wenn ich beispielsweise in realem Code zu einer anderen Datenbankclient-Implementierung wechseln muss, muss ich nur eine Zeile ändern, anstatt nach Verweisen auf den Konstruktor zu suchen.
Natürlich funktioniert es genau wie bei Jons Ansatz nicht mit Code von Drittanbietern, den Sie nicht ändern können oder dürfen.