Java 在多线程环境中使用JUnit的奇怪问题
在多线程环境中使用JUnit时,我遇到了一个奇怪的问题。下面的代码应该失败,但它实际上在eclipse中传递Java 在多线程环境中使用JUnit的奇怪问题,java,multithreading,junit,Java,Multithreading,Junit,在多线程环境中使用JUnit时,我遇到了一个奇怪的问题。下面的代码应该失败,但它实际上在eclipse中传递 public class ExampleTest extends TestCase { private ExecutorService executor = Executors.newFixedThreadPool(10); private volatile boolean isDone = false; public void test() throws
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无法处理多线程单元测试,但这两段代码之间有什么区别?谢谢看一看(从17:09开始),它解释了JUnit和线程可能遇到的问题
我认为,在您的情况下,
get()
抛出一个ExecutionException
,这就是第二个测试失败的原因。在第一个测试用例中,jUnit没有看到异常。jUnit无法看到除运行测试的线程之外的其他线程中发生的异常。在第一种情况下,通过调用fail
发生异常,异常发生在执行器运行的单独线程中。因此它对JUnit不可见,并且测试通过
在第二种情况下,相同的异常发生在由执行器运行的单独线程中,但是当您调用future.get
时,该异常会有效地“报告回”测试线程。这是因为future.get
如果由于任何异常而导致未来计算失败,则抛出ExecutionException
。JUnit能够看到此异常,因此测试失败。还有一个有趣的事实,Eclipse和IDEA可以在JUnit测试运行程序中生成VM,并最终调用system.exit()。这意味着如果您在测试中没有正确等待(就像您在上面睡觉并希望任务已完成时的情况一样),它可能会意外退出。有意思,但不完全是你要的
请参阅此以了解详细信息 正如@abhin4v所指出的,新线程中的异常会被吞没。您可以尝试提供自己的fail
——与顶级线程同步的方法,非常类似于您的示例中的get()
但是不需要使用未来,只需写入一个表示失败的共享变量,然后使用newThreadId.join()
。除此之外,我不知道在普通JUnit中还有什么其他方法可以解决这个问题。@zjffdu@ShiDoiSi指出,如果您有一个要断言或失败的工作线程,Thread.join()可以正常工作
如果您有多个工作线程,或者您希望更方便一些,那么有一个JUnit扩展用于执行多线程断言:
祝你好运
public class ExampleTest extends ConcurrentTestCase {
private ExecutorService executor = Executors.newFixedThreadPool(10);
public void test() throws Throwable {
executor.submit(new Runnable() {
@Override
public void run() {
try {
threadFail("Failure message");
} finally {
resume();
}
}
});
threadWait();
}
}