我有一个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?
答案 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();
}};
}
}