【发布时间】:2011-02-19 16:22:01
【问题描述】:
当我测试创建子线程的方法的执行时,JUnit 测试在子线程之前结束并杀死它。
如何强制 JUnit 等待子线程完成执行?
【问题讨论】:
标签: java unit-testing multithreading junit
当我测试创建子线程的方法的执行时,JUnit 测试在子线程之前结束并杀死它。
如何强制 JUnit 等待子线程完成执行?
【问题讨论】:
标签: java unit-testing multithreading junit
在阅读了问题和一些 cmets 之后,您似乎需要的是一种用于单元测试异步操作的技术。 doSomething() 立即返回,但您希望测试代码等待其完成,然后进行一些验证。
问题是测试不知道调用产生的线程,所以显然它没有等待它们的方法。人们可以想出许多复杂(并且可能有缺陷)的方法来解决这个问题,但我认为这里存在设计问题。单元测试应该模拟一些 API 的客户端,并且它不应该假设任何关于实现的东西;它应该只测试 API 及其文档所反映的功能。因此,我会避免尝试检测和跟踪异步调用创建的线程。相反,如果需要,我会改进测试类的 API。异步调用所属的类应该提供一些检测终止的机制。我能想到 3 种方法,但可能还有更多:
允许注册一个在操作完成后得到通知的监听器
提供操作的同步版本。实现可以调用异步版本,然后阻塞直到完成。如果类不应该公开这样的方法,则可以将其可见性降低为包保护,以便测试可以访问它。
在某些可见对象上使用等待通知模式。
如果类没有提供这样的机制,那么它就不是真正可测试的,更糟糕的是,它可能也不是很可重用。
【讨论】:
尝试在创建的线程上使用thread.join()。这将等待该线程终止。
编辑:为避免这种情况,请在测试中尝试Thread.getThreadGroup().setDaemon(true);,或者在setUp() 方法中尝试。不过我还没有测试过。
当最后一个线程停止或最后一个线程组被销毁时,守护线程组会自动销毁。
不过,我想知道 JUnit 是否会在测试完成后立即调用 System.exit() 或其他什么。
【讨论】:
@Eyal 概述的基本技术是 ConcurrentUnit 的用途。一般用法是:
有关详细信息,请参阅 ConcurrentUnit 页面。
【讨论】:
也许用 ExecutorService 将您的线程分组,然后使用 shutdown 和 awaitTermination 方法?
条件是使用 Runnable 或 Future,而不是线程本身。
【讨论】:
while (s.isRunning()) {
try {
Thread.sleep(SLEEP_TIME);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
您可以尝试阻止 JUnit 线程并让它等待您的线程完成。 Thread.sleep() 是必需的,这样您的线程就不会占用 CPU。在这个例子中 s 将是你的线程,你需要有一个 isRunning() 方法,这样你就可以每隔 SLEEP_TIME 毫秒检查线程是否仍在运行。我知道这不是最好的解决方案,但是如果您只有 2 个线程并且您不希望 JUnit 杀死您的线程,那么这是可行的。 while 循环导致此 JUnit 线程保持活动状态并等待您的其他线程完成。
【讨论】:
在java中,尝试使用CountDownLatch让主线程等到子线程完成。
@Test
public void myTest() {
CountDownLatch countDownLatch = new CountDownLatch(1);
new Thread(new Runnable() {
@Override
public void run() {
//write your logic here
countDownLatch.countDown();
}
}).start();
//wait until the child thread completed.
countDownLatch.await();
}
【讨论】: