我在多线程环境下使用JUnit时遇到了一个奇怪的问题。下面的代码应该会失败,但实际上它在Eclipse中通过了。
public class ExampleTest extends TestCase {
private ExecutorService executor = Executors.newFixedThreadPool(10);
private volatile boolean isDone = false;
public void test() throws InterruptedException, ExecutionException {
executor.submit(new Runnable() {
@Override
public void run() {
try {
fail();
} finally {
isDone = true;
}
}
});
while (!isDone) {
Thread.sleep(1000);
}
}
}
这是另一段代码,这里我使用Future.get()来等待线程停止,在这种情况下,它将失败。
public class ExampleTest extends TestCase {
private ExecutorService executor = Executors.newFixedThreadPool(10);
private volatile boolean isDone = false;
public void test() throws InterruptedException, ExecutionException {
Future future=executor.submit(new Runnable() {
@Override
public void run() {
try {
fail();
} finally {
isDone = true;
}
}
});
future.get();
}
}
我在谷歌上搜索了一下,发现JUnit不能处理多线程单元测试,但是这两段代码有什么区别呢?谢谢
4条答案
按热度按时间vlju58qv1#
JUnit无法看到在运行测试的线程以外的线程中发生的异常。在第一种情况下,通过调用
fail
发生异常,它发生在executor
运行的单独线程中。因此,它对JUnit不可见,测试通过。在第二种情况下,相同的异常发生在
executor
运行的单独线程中,但当您调用future.get
时,该异常实际上被“报告回”给测试线程。这是因为如果未来的计算由于任何异常而失败,future.get
将抛出ExecutionException
。JUnit能够看到该异常,因此测试失败。v64noz0r2#
正如@abhin4v所指出的,新线程中的异常会被吞噬,你可以试着提供你自己的
fail
-方法,它与顶层线程同步,就像你的get()
例子一样。但是不需要使用Futures,只需要写入一个指示失败的共享变量并使用
newThreadId.join()
即可,除此之外,我不知道在普通JUnit中还有什么其他方法可以解决这个问题。unhi4e5o3#
看一下http://www.youtube.com/watch?v=wDN_EYUvUq0(从17:09开始),它解释了JUnit和线程可能遇到的问题。
我认为,在您的例子中,
get()
抛出了一个ExecutionException
,这就是第二个测试失败的原因,在第一个测试中,jUnit没有看到异常。4nkexdtk4#
还有一个有趣的事实,Eclipse和IDEA可以在他们的junit测试运行器中生成一个VM,并最终在其上调用system.exit()。这意味着,如果您在测试中没有正确等待(例如,当您在上面睡觉并希望任务已经完成时),它可能会意外退出。有趣,但不完全是您所要求的!
有关详细信息,请参阅此link...