在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()。 这意味着如果您在测试中没有正确等待(例如,当您在上面睡觉并希望任务已完成时),它可能会意外退出。 有趣,但不完全是你问的!
请参阅此链接了解详情……