JMockit:Singleton类,测试顺序

时间:2014-10-30 08:04:52

标签: java junit singleton private-members jmockit

我有一个Singleton类来测试:

public class Singleton {
    private static Singleton instance;

    private List<String> list;

    private Singleton() {

    }

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                instance = new Singleton();
            }
        }
        return instance;
    }

    public boolean methodOne() {
        if (list == null) {
            list = new ArrayList<String>();
            list = SomeClass.fillListOne();
        }
        return SomeClass.verifyList(list);
    }

    public boolean methodTwo() {
        if (list == null) {
            list = new ArrayList<String>();
            list = SomeClass.fillListTwo();
        }
        return SomeClass.verifyList(list);
    }
}

使用以下测试类:

@RunWith(JMockit.class)
public class SingletonTest {
    @Test
    public void testOne(final @Mocked SomeClass someClass) {
        Singleton.getInstance().methodOne();
        new Verifications() {
            {
                SomeClass.fillListOne();
            }
        };

    }

    @Test
    public void testTwo(final @Mocked SomeClass someClass) {
        Singleton.getInstance().methodTwo();
        new Verifications() {
            {
                SomeClass.fillListTwo();
            }
        };
    }
}

如果我只执行&#34; testOne&#34;或者只是&#34; testTwo&#34;,测试通过。如果我执行所有测试,它只传递执行的第一个方法。如何设置&#34; list&#34;属性为null,例如在@Before方法中?如何在没有setter的情况下使用Singleton或私有成员进行Deencapsulation?

2 个答案:

答案 0 :(得分:3)

该课程不是特别容易受到考验。如果你有选择,我建议你改写它。 (使用模拟静态方法调用进行测试是一个维护噩梦,我也普遍不喜欢所有单例 - 它们似乎无处不在,无论它们是否应该使用)。

无论如何,the documentation suggests你可以做这样的事情(为了便于阅读,我还添加了一个额外的字段,但你不必这样做):

@RunWith(JMockit.class)
public class SingletonTest {
    private Singleton instance;

    @Before
    public void initialise() {
        Deencapsulation.setField(Singleton.class, "instance", null);
        instance = Singleton.getInstance();
    }

    @Test
    public void testOne(final @Mocked SomeClass someClass) {
        instance.methodOne();
        new Verifications() {
            {
                SomeClass.fillListOne();
            }
        };
    }
    // ...other tests...
}

答案 1 :(得分:0)

我发现现有答案存在问题:即使调用了SomeClass的方法 ,测试也会通过。这违背了测试的目的:当且仅当调用方法SomeClass.fillListOne()和SomeClass.fillListTwo()时,它应该传递

以下是使用JMockit验证调用的方法,在依赖项SomeClass上使用NonStrictExpectations返回null。我已经使用问题中提供的相同示例对其进行了测试,它在未进行调用时失败并在调用时通过:

@RunWith(JMockit.class)
public class SingletonTest {
    // capturing ensures Jmockit will mock all SomeClass instances.
    @Capturing
    private SomeClass someClass;

    @Before
    public void prepareTests() {
        new NonStrictExpectations() {{
            SomeClass.fillListOne(); result = null;
            SomeClass.fillListTwo(); result = null;
        }};
    }

    @Test
    public void testOne() {
        Singleton.getInstance().methodOne();
        new Verifications() {{
            SomeClass.fillListOne();
        }};
    }

    @Test
    public void testTwo() {
        Singleton.getInstance().methodTwo();
        new Verifications() {{
            SomeClass.fillListTwo();
        }};
    }
}