在多线程环境中使用JUnit的奇怪问题

时间:2010-10-28 04:53:18

标签: 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 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无法处理多线程单元测试,但这两段代码之间的区别是什么?感谢

5 个答案:

答案 0 :(得分:7)

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

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

答案 1 :(得分:2)

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

如果你有多个工作线程,或者你想要更方便一点,那么有一个JUnit扩展用于执行多线程断言: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();
    }
}
祝你好运

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

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

有关详细信息,请参阅此link