4

我想用以下方法测试单例类的行为:

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 already initialized");
        }

        instance = new SomeSingleton(value1, value2);
    }

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

        return instance;
    }
}

然后我有一个带有几个测试方法的测试类,它们调用init了几次:

@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();
        [...]
    }
}

当我这样做时,我总是IllegalStateException在第二次测试中获得,因为instance != null.

如何init在一个测试类中运行多个测试?

testGetInstanceSunnyDay将and放在testGetInstanceRainyDay2 个单独的类中解决了这个问题,但我想知道是否有更好的解决方案。

4

3 回答 3

5

从根本上说,单例很难测试,正是因为这种事情。您可以添加一个clearStateForTesting方法:

static void clearStateForTesting() {
    instance = null;
}

...但如果可能的话,我建议您首先避免使用单例模式。

另请注意,您的单例实现目前不是线程安全的。如果你真的需要使用单例,有明显更好的实现。

于 2013-09-20T13:21:20.187 回答
2

尽管我同意 Jon 的观点,但另一种选择是使用ReflectionTestUtils或一般反射将instance字段设置为null. 知道如果字段名称更改,这可能会很脆弱。

于 2013-09-20T13:56:26.437 回答
0

鉴于它是一个单例,该init方法作为公共方法毫无意义。制作它private并仅getInstance在您的单元测试中使用。

于 2013-09-20T19:21:32.257 回答