Ich habe eine Ressourcendatei mit einigen Einstellungen. Ich habe eine ResourceLoader-Klasse, die die Einstellungen aus dieser Datei lädt. Diese Klasse ist derzeit eine eifrig instanziierte Singleton-Klasse. Sobald diese Klasse geladen wird, liest sie die Einstellungen aus der Datei (Dateipfad, der als konstantes Feld in einer anderen Klasse gespeichert ist). Einige dieser Einstellungen sind nicht für Unit-Tests geeignet. ZB habe ich in dieser Datei eine Thread-Ruhezeit, die Stunden für den Produktionscode betragen kann, aber ich möchte, dass sie für Unit-Tests einige Millisekunden beträgt. Ich habe also eine andere Testressourcendatei, die andere Werte hat. Meine Frage ist, wie ich beim Testen von Einheiten die Hauptressourcendatei mit dieser Testdatei austauschen soll. Das Projekt ist ein Maven-Projekt und ich verwende testng als Test-Framework. Dies sind einige der Ansätze, die ich '
Verwenden Sie @BeforeSuite und ändern Sie die Konstantenvariable FilePath so, dass sie auf die Testdatei verweist. Verwenden Sie @AfterSuite, um sie wieder auf die Originaldatei zu verweisen. Dies scheint zu funktionieren, aber ich denke, da die ResourceLoader-Klasse eifrig instanziiert wird, gibt es keine Garantie dafür, dass die @ BeforeSuite-Methode immer ausgeführt wird, bevor die ResourceLoader-Klasse geladen wird, und daher möglicherweise alte Eigenschaften geladen werden, bevor der Dateipfad geändert wird. Obwohl die meisten Compiler eine Klasse nur laden, wenn dies erforderlich ist, bin ich mir nicht sicher, ob dies eine Java-Spezifikationsanforderung ist. Theoretisch funktioniert dies möglicherweise nicht für alle Java-Compiler.
Übergeben Sie den Pfad der Ressourcendatei als Befehlszeilenargument. Ich kann den Pfad der Testressourcendatei als Befehlszeilenargument in der todsicheren Konfiguration im POM hinzufügen. Das scheint etwas übertrieben.
Verwenden Sie den Ansatz in 1. und machen Sie ResourceLoader faul instanziiert. Dies garantiert, dass ResourceLoader die richtige Datei lädt, wenn @BeforeMethod vor dem ersten Aufruf von ResourceLoader.getInstance (). GetProperty (..) aufgerufen wird. Dies scheint besser zu sein als die ersten beiden Ansätze, aber ich denke, dass es hässlich ist, eine Singleton-Klasse faul instanziiert zu machen, da ich kein einfaches Muster wie eine Aufzählung und dergleichen verwenden kann (wie es bei eifriger Instanziierung der Fall ist).
Dies scheint ein häufiges Szenario zu sein. Wie geht man am häufigsten vor?
quelle
Antworten:
Alle Singletons, die entweder eifrig oder träge instanziiert werden, sind Anti-Patterns . Die Verwendung von Singletons erschwert das Testen von Einheiten, da es keine einfache Möglichkeit gibt, Singleton zu verspotten.
Mock statische Methode
Eine Problemumgehung besteht darin, PowerMock zu verwenden, um die statische Methode zu verspotten, die eine Singleton-Instanz zurückgibt.
Verwenden Sie die Abhängigkeitsinjektion
Eine bessere Lösung ist die Verwendung der Abhängigkeitsinjektion. Wenn Sie bereits ein Abhängigkeitsinjektionsframework (z. B. Spring, CDI) verwenden, überarbeiten Sie den Code, um
ResourceLoader
eine verwaltete Bean mit Scope-Singleton zu erstellen .Wenn Sie kein Abhängigkeitsinjektionsframework verwenden, besteht ein einfaches Refactoring darin, mit dem Singleton Änderungen an allen Klassen vorzunehmen
ResourceLoader
:Und dann in Unit-Tests
ResourceLoader
mit Mockito verspottenKonfiguration externalisieren
Ein anderer Ansatz besteht darin, eine Datei mit Testeinstellungen unter zu platzieren
src/test/resources
. Wenn Sie Einstellungen insrc/main/resources/application.properties
speichern,src/test/resources/application.properties
wird diese von einer Datei überschrieben.Es ist auch eine gute Idee, die Konfiguration in eine Datei zu verlagern, die nicht in einer JAR gepackt ist. Auf diese Weise enthält die Datei
src/main/resources/application.properties
Standardeigenschaften, und eine mit dem Befehlszeilenparameter übergebene Datei überschreibt diese Eigenschaften. Daher wird eine Datei mit Testeigenschaften auch als Befehlszeilenparameter übergeben. Sehen Sie, wie Spring mit der externalisierten Konfiguration umgeht .Verwenden Sie die Java-Systemeigenschaften
Noch einfacher ist es, das Überschreiben von Standardeigenschaften mit Systemeigenschaften in der Methode zuzulassen
ResourceLoader.getInstance().getProperty()
und die Testeigenschaften auf diese Weise zu bestehenquelle
Überprüfen Sie, ob Sie in jUnit
Sie können zur Laufzeit auch überprüfen, ob jUnit ausgeführt wird, und dann den Pfad austauschen. Das würde so funktionieren ( ungetestet ):
quelle