我已阅读此帖:Is there a way in JMockit to call the original method from a mocked method?
但推荐的解决方案会引发NPE。这是我的来源
static Map<String, Boolean> detectDeadlocks(int timeInSeconds) {
final Map<String, Boolean> deadlockMap = new LinkedHashMap<>();
new Timer().schedule(new TimerTask() {
@Override
public void run() {
// I want to check if the method is run.
**deadlockMap.put("deadlock", isDeadlockAfterPeriod());**
}
}, timeInSeconds * 1000);
return deadlockMap;
}
我希望能够在单元测试中调用isDeadlockAfterPeriod
。这是我在单元测试中嘲笑的静态方法。
我的单元测试代码
@Test
public void testDetectDeadlocks() throws Exception {
new Expectations(){
{
// Called from inside the TimerTask.
ClassUnderTest.isDeadlockAfterPeriod();
result = false;
}
};
TimerMockUp tmu = new TimerMockUp();
Deadlocks.detectDeadlocks(0);
Assert.assertEquals(1, tmu.scheduleCount);
}
class TimerMockUp extends MockUp<Timer> {
int scheduleCount = 0;
@Mock
public void $init() {}
@Mock
public void schedule(Invocation invocation, TimerTask task, long delay) {
scheduleCount ++;
invocation.proceed(); // Trying to call the real method, but this throws a NPE.
}
}
Eclipse中的JUnit可以看到错误堆栈跟踪。
java.lang.NullPointerException
at com.myproject.test.DeadlocksTest$TimerMockUp.schedule(DeadlocksTest.java:78)
at com.myproject.test.Deadlocks.detectDeadlocks(Deadlocks.java:41)
at com.myproject.test.DeadlocksTest.testDetectDeadlocks(DeadlocksTest.java:86)
答案 0 :(得分:0)
你的问题是你也伪造了Timer的构造函数(而不仅仅是schedule
方法)。
通过这样做,您正在阻止Timer的正确初始化,并且当您正在使用其实际实现时,它无法这样做。
具体而言(使用我拥有的资源),您阻止了queue
字段的初始化,该mainLoop()
字段用于TimerTask.run()
方法(将调用Deadlocks
的方法)。
此外,您需要对isDeadlockAfterPeriod
类进行部分模拟,因为我知道public class Deadlocks {
public static Map<String, Boolean> detectDeadlocks(int timeInSeconds) {
final Map<String, Boolean> deadlockMap = new LinkedHashMap<>();
new Timer()// this will be the real constructor
.schedule( // this will be first mocked, then really executed
new TimerTask() {
@Override
public void run() {
deadlockMap.put("deadlock", isDeadlockAfterPeriod()); // this will put false after the mock is called
}
}, timeInSeconds * 1000);
return deadlockMap;
}
public static Boolean isDeadlockAfterPeriod() {
return true; // this, we will mock it
}
}
也是该类的静态方法。
我会在这里留下一个有效的例子:
<强> Deadlocks.class 强>
@RunWith(JMockit.class)
public TestClass{
@Test
public void testDetectDeadlocks() throws Exception {
new Expectations(Deadlocks.class){ // do partial mocking of the Deadlock class
{
// Called from inside the TimerTask.
Deadlocks.isDeadlockAfterPeriod();
result = false;
}
};
// prepare the fake
TimerMockUp tmu = new TimerMockUp();
// execute the code
Map<String, Boolean> result = Deadlocks.detectDeadlocks(0);
// assert results
assertThat(tmu.scheduleCount, is(1));
assertThat(result.size(), is(1));
assertThat(result.get("deadlock"), is(false));
}
class TimerMockUp extends MockUp<Timer> {
int scheduleCount = 0;
@Mock
public void schedule(Invocation invocation, TimerTask task, long delay) {
scheduleCount ++;
invocation.proceed();
}
}
}
测试类
dict
通常,在伪装构造函数时要非常小心,因为可能会使实例处于不一致状态。