4 Stimmen

Wie testet man Singletons in einer Testklasse?

Ich möchte das Verhalten einer Singleton-Klasse mit folgenden Methoden testen:

public class SomeSingleton
{
    private final static int DEFAULT_VALUE1 = ...;
    private final static int DEFAULT_VALUE2 = ...;

    private static SomeSingleton instance;

    public static void init(int value1, int value2)
    {
        if (instance != null)
        {
            throw new IllegalStateException("SomeSingleton bereits initialisiert");
        }

        instance = new SomeSingleton(value1, value2);
    }

    public static getInstance()
    {
        if (instance == null)
        {
            init(DEFAULT_VALUE1, DEFAULT_VALUE2);
        }

        return instance;
    }
}

Und dann habe ich eine Testklasse mit mehreren Testmethoden, die init mehrmals aufrufen:

@RunWith(PowerMockRunner.class)
@PrepareForTest(SomeSingleton.class)
public class SomeSingletonTest {
    @Test
    public void testGetInstanceSunnyDay()
    {
        [...]
        SomeSingleton.init(...);
        [...]
        SomeSingleton.getInstance();
        [...]
    }

    @Test
    public void testGetInstanceRainyDay()
    {
        [...]
        SomeSingleton.init(...); // IllegalStateException
        [...]
        SomeSingleton.getInstance();
        [...]
    }
}

Wenn ich es auf diese Weise mache, bekomme ich immer die IllegalStateException im zweiten Test, weil instance != null.

Wie kann ich mehrere Tests, die init involvieren, in einer Testklasse durchführen?

Das Aufteilen von testGetInstanceSunnyDay und testGetInstanceRainyDay in 2 separate Klassen löst das Problem, aber ich frage mich, ob es eine bessere Lösung gibt.

5voto

Jon Skeet Punkte 1325502

Grundsätzlich sind Singletons schwer zu testen, genau wegen solcher Dinge. Du könntest eine clearStateForTesting Methode hinzufügen:

static void clearStateForTesting() {
    instance = null;
}

... aber ich würde vorschlagen, dass du das Singleton-Muster im ersten Schritt vermeidest, wenn möglich.

Beachte auch, dass deine Singleton-Implementierung momentan nicht thread-sicher ist. Es gibt deutlich bessere Implementierungen, wenn du wirklich ein Singleton verwenden musst.

2voto

John B Punkte 31552

Auch wenn ich mit Jon übereinstimme, ist die andere Option, ReflectionTestUtils oder Reflektion im Allgemeinen zu verwenden, um das instance-Feld auf null zu setzen. Zu beachten ist, dass dies brüchig sein kann, wenn sich der Feldname ändert.

0voto

Raedwald Punkte 43209

Angegeben, dass es sich um ein Singleton handelt, macht die init-Methode keinen Sinn als öffentliche Methode. Machen Sie sie private und verwenden Sie nur getInstance in Ihren Unittests.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X