在multithreading环境中使用JUnit的奇怪问题

在multithreading环境中使用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(); } } 

我用Google搜索并发现JUnit无法处理multithreadingunit testing,但这两段代码之间有什么区别? 谢谢

JUnit无法查看除运行测试的线程之外的线程中发生的exception。 在第一种情况下,通过调用fail发生exception,它发生在executor运行的单独线程中。 因此,它对JUnit不可见并且测试通过。

在第二种情况下,在executor运行的单独线程中发生相同的exception,但是当您调用future.get时,exception会有效地“报告回”测试线程。 这是因为如果由于任何exception导致未来的计算失败, future.get将抛出ExecutionException 。 JUnit能够看到此exception,因此测试失败。

@zjffdu正如@ShiDoiSi所指出的,如果你有一个你想断言或失败的工作线程,Thread.join()可以正常工作。

如果你有多个工作线程,或者你想要更方便一点,那么有一个JUnit扩展用于执行multithreading断言: ConcurrentUnit :

 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(); } } 

祝好运

正如@ abhin4v指出的那样,新线程中的exception会被吞噬。 您可以尝试提供与顶级线程同步的自己的fail -method,就像使用get()示例一样。

但是没有必要使用Futures,只需写入指示失败的共享变量并使用newThreadId.join() 。 除此之外,我不知道在普通的JUnit中有任何其他解决方法。

请查看http://www.youtube.com/watch?v=wDN_EYUvUq0(17:09开始),它解释了您可以使用JUnit和线程获得的问题。

我认为,在你的情况下, get()会抛出ExecutionException ,这就是第二次测试失败的原因。 在第一个测试用例中,jUnit没有看到exception。

还有一个有趣的事实,Eclipse和IDEA可以在他们的junit测试运行器中生成一个VM,并最终调用它上面的system.exit()。 这意味着如果您在测试中没有正确等待(例如,当您在上面睡觉并希望任务已完成时),它可能会意外退出。 有趣,但不完全是你问的!

请参阅此链接了解详情……