我正在寻找一种在JMockit中注入类内部私有字段的方法,同时保持触发真实方法的能力。我使用JMockit提供的@Injectable
和@Tested
。但不知何故,注入的实例无法调用真正的方法。
示例测试:
public class TestClass {
public static class DoSomething {
private Call callee;
public void execute() {
callee.call();
}
}
public static class Call {
public void call() {
System.out.println("real");
}
}
@Tested DoSomething doSomething;
@Injectable Call call;
// nothing happens
@Test
public void testRealCall() {
doSomething.execute();
}
// invocation doesn't help either
@Test
public void testRealCallSecondTry() {
new MockUp<Call>() {
@Mock
@SuppressWarnings("unused")
public void call(Invocation inv) {
inv.proceed();
}
};
doSomething.execute();
}
// this works, but requires redundant methods
@Test
public void testRealCallThirdTry() {
new MockUp<Call>() {
@Mock
@SuppressWarnings("unused")
public void call() {
System.out.println("real");
}
};
doSomething.execute();
}
@Test
public void testFakeCall() {
new MockUp<Call>() {
@Mock
@SuppressWarnings("unused")
public void call() {
System.out.println("fake");
}
};
doSomething.execute();
}
}
在这里,DoSomething
包装Call
实例,它提供了一种打印消息的方法。四个测试用例的理想输出是:
real
real
real
fake
然而,实际情况是只有 3 和 4 有效,打印:
real
fake
这将显示是否使用 @Injectable
创建实例。如果不将旧方法主体复制并粘贴到模拟版本中,则无法直接调用原始方法。这似乎真的很尴尬。有解决方法吗?
我的理解是,如果你使用@Injectable你只会得到一个空的模拟,然后你不能再调用原始方法。
我将使用的解决方法是像这样"手动"进行注入:
public class TestClass {
public static class DoSomething {
private Call callee;
public void execute() {
callee.call();
}
}
public static class Call {
public void call() {
System.out.println("real");
}
}
@Tested DoSomething doSomething;
//@Injectable Call call;
// nothing happens
@Test
public void testRealCall() {
Deencapsulation.setField(doSomething, "callee", new Call());
doSomething.execute();
}
// invocation doesn't help either
@Test
public void testRealCallSecondTry() {
new MockUp<Call>() {
@Mock
@SuppressWarnings("unused")
public void call(Invocation inv) {
inv.proceed();
}
};
Deencapsulation.setField(doSomething, "callee", new Call());
doSomething.execute();
}
// this works, but requires redundant methods
@Test
public void testRealCallThirdTry() {
new MockUp<Call>() {
@Mock
@SuppressWarnings("unused")
public void call() {
System.out.println("real");
}
};
Deencapsulation.setField(doSomething, "callee", new Call());
doSomething.execute();
}
@Test
public void testFakeCall() {
new MockUp<Call>() {
@Mock
@SuppressWarnings("unused")
public void call() {
System.out.println("fake");
}
};
Deencapsulation.setField(doSomething, "callee", new Call());
doSomething.execute();
}
}
当我遇到同样的问题时,我遇到了这个问题。但是,现有的答案不适用于较新版本的JMockit。
如果测试类中的字段用 @Inject
注释,则测试类中需要相应的@Injectable
。这意味着删除@Injectable
,而是使用另一个答案中建议的MockUp
模拟类是行不通的。JMockit将抱怨"缺少现场@Injectable..."。
相反,需要做的是将@Injectable
注释更改为@Tested
注释,即更改此注释
@Injectable Call call;
自
@Tested Call call;
call
成为一个真实的实例,JMockit 不会抱怨丢失@Injectable
。如果您需要在call
中模拟某些方法,则可以像往常一样使用MockUp
来完成。
new MockUp<Call>() {
@Mock
public void someMethodToMock() {
}
};