【发布时间】:2015-09-29 02:29:18
【问题描述】:
我有一个实现Runnable 的类,称为DoThingInALoop。它被提供给第二个类,它将从中创建一个线程,调用这个线程Boss。 Boss 可以告诉 runnable 退出并让线程终止。稍后,它可以使用相同的DoThingInALoop 创建一个新线程。
当我为Boss 编写单元测试时,我想模拟DoThingInALoop,因为它不是被测对象。然而,DoThingInALoop 扩展了一个类Loop,而Loop 的代码实际上是在Boss 产生的线程中执行的。该代码当然会遇到NullPointerExceptions,因为没有设置任何成员变量,因为该对象被模拟了。
如何防止 Java 的 Thread“看穿”模拟?
public class Loop implements Runnable {
private final Object member = new Object();
public final void run() {
// This code runs, but it shouldn't
synchronized (member) { // Throws NPE
...
}
// Hook for subclasses
try {
subclassRun();
} finally {
// Mandatory cleanup (unrelated to question)
}
}
public class DoThingInALoop extends Loop {
public void subclassRun() { ... }
public void stopDoingThingsInALoop() {
// Set instance member that on next loop iteration signals thread to return
}
}
public class Boss {
private final DoThingsInALoop toBeMocked;
public Boss(final DoThingsInALoop toBeMocked) {
this.toBeMocked = toBeMocked;
}
public void start() {
// Simplified
new Thread(toBeMocked).start();
}
public void stop() {
toBeMocked.stopDoingThingsInALoop();
}
}
public class TestClass {
@Test
public void aTest() {
// Setup Mocks
DoThingsInALoop mockLoop = mock(DoThingsInALoop.class);
Boss boss = new Boss(mockLoop);
// Run test
boss.start();
// After the above line runs, a new thread is started and
// the run() method of `Loop` executes until the NPE
// is hit when it attempts to access a member variable
// which is of course not set because it is a mocked object
...
}
}
【问题讨论】:
-
请发布可重现的内容。
Loop#run不会被调用。一些假的DoThingInALoopProxyClass#run将被调用,不会做任何事情。 -
除非你的
run方法实际上是final... -
你试过在你的模拟中存根
run()方法吗?doNothing().when(mockLoop).run(); -
@SotiriosDelimanolis 抱歉,我正在总结真实的代码。
Loop.run()是最终的并调用另一个方法,该方法是DoThingInALoop的挂钩以进行扩展。我会更新问题。 -
@Ruben 我忘了提到
Loop.run()是最终的,因此不能被嘲笑。
标签: java multithreading unit-testing mockito