2010-01-30 18 views
17

Ich habe ein eigenständiges Singleton, das den Test erfolgreich besteht. Bei einer Gruppe von Tests schlägt dies fehl, da nach dem Definieren eines Singletons die Instanz nicht zurückgesetzt werden kann.Verschiedene Singleton-Instanzen mit JUnit-Tests

Irgendwelche Ideen, wie man das macht?

Antwort

9

Verwenden Sie kein Singleton.

Der einzige Unterschied zwischen einer Singleton-Variablen und einer globalen Variablen besteht darin, dass das Singleton versucht, eine einzelne Instanz zu erzwingen (indem beispielsweise der Konstruktor privat gemacht wird).

Machen Sie den Konstruktor stattdessen öffentlich und schreiben Sie Tests mit neuen Instanzen. Verwenden Sie in Ihrem tatsächlichen Programm getInstance(), um die kanonische globale Instanz zu erhalten (oder verwenden Sie einen IOC-Container).

Und denken Sie daran, dass singletons are pathological liars.

Wenn Sie mit der Idee eines Singleton noch zu vertraut sind, können Sie den Konstruktor öffentlich machen, indem Sie eine öffentliche (und statische) Factory-Methode hinzufügen, um Instanzen auf eine Weise zu erstellen, die nicht zufällig verwendet werden kann. zB:

public static MyClass TEST_CreateInstance() { 
    return new MyClass(); 
} 
3

Sie können eine Methode hinzufügen, um den Singleton zu zerstören, zum Beispiel destroyMe(); wo du alles deinitialisierst und die Instanz des Singletons auf null setzt.

public void destroyMe(){ 
    this.instance = null; 
    //-- other stuff to turn it off. 
} 

ich allerdings Synchronisationsprobleme verlassen;)

Aber warum müssen Sie Ihre Singletons für jeden Test neu zu initialisieren? Es sollte nicht basierend auf dem Konzept des Singleton unterscheiden.

10

Ich nehme an, Sie haben ein privates statisches Feld innerhalb Ihrer Singleton-Klasse, um die initialisierte Instanz zu speichern.

Wenn Sie Ihren Code nicht ändern möchten, können Sie eine Teardown-Methode definieren, die nach jedem Test ausgeführt wird, und bei dieser Methode setzen Sie dieses statische Feld über Reflektion auf null, wie in here gezeigt.

+1

-1, IMO dies macht eine schlechte Situation schlechter – orip

+13

+1 für eine tatsächliche Lösung geben. Ich habe keine Kontrolle über den Code von Drittanbietern, der ein Singleton ist, und brauche Lösungen, die nicht darauf hingewiesen werden, wie es gemacht werden sollte. – eis

1

im Allgemeinen Vorsicht vor Singletons, meist sind sie böse, schlechtes Design und neigen dazu, große yucky globale Variablen darstellen (was schlecht für die Wartung ist).

noch Tests an Ort und Stelle zu bekommen zuerst können Sie tun:

 

static setInstance(...){ //package visibility or in difficult cases you have to use public 
    instance = ...; 
} 
 

wie gesagt diese eine Abhilfe mehr ist. Also teste zuerst den Platz, aber dann ändere den Weg vom Singleton-Muster.

0

Singleton-Instanz muss durch Test an SUT übergeben werden - auf diese Weise erstellen Sie Singleton (und zerstören) für jeden Test. IoC und Mockito zu übernehmen, würde diesen Ansatz fast trivial machen.

1

I empfehlen von Singletons weg als Designmuster bewegt und mit Singleton als Rahmen (Dependency Injection). Dies würde Ihr Problem einfach verschwinden lassen.

Aber vorausgesetzt, Sie stecken in der Welt der Singletons, dann haben Sie ein paar Optionen abhängig davon, ob Sie den Singleton oder die Abhängigkeit testen.

Wenn Sie das abhängige Element testen, können Sie das Singleton mit PowerMock und JMockIt verspotten. Sehen Sie meine previous post über Mocking Runtime.getRuntime für Anweisungen dazu, wie das geht.

Wenn Sie den Singleton testen, müssen Sie die Konstruktionsregeln lockern oder dem Singleton eine "Reset" -Methode geben.

1

Spring liefert die DirtiesContext-Annotation für diesen speziellen Anwendungsfall, in dem Sie für jeden Testfall neue Instanzen der Singleton-Beans benötigen. Es erstellt im Grunde einen neuen Anwendungskontext für jeden Testfall/jede Testklasse, auf die diese Annotation angewendet wurde.

Verwandte Themen