我正在尝试编写需要多线程的单元测试。但是,似乎线程只是停止执行的一部分。请考虑以下代码:
public class Test {
@org.junit.Test
public void TestThreads() {
new Thread(new Runnable() {
public void run() {
for (int i = 1; i < 1000; i++) System.out.println(i);
}
}).start();
}
}
如果我运行此单元测试,它通常会停止在140-180之间显示输出。如果我将此代码转换为常规类并运行它,它可以正常工作。有没有人知道我在这里缺少什么?
谢谢, - 安德鲁。
答案 0 :(得分:23)
您可以使用Thread.join()
来阻止测试在新线程完成任务之前完成:
@org.junit.Test
public void TestThreads() throws InterruptedException {
Thread t = new Thread(new Runnable() {
public void run() {
for (int i = 1; i < 1000; i++) System.out.println(i);
}
});
t.start();
t.join();
}
通常,JVM将在最后一个非守护程序线程终止时终止。您可能希望在线程上简单地调用t.setDaemon(false)
会阻止JVM在任务完成之前退出。 但是,当主线程完成时,junit将call System.exit()。
正如Gus在评论中指出:“你需要join()因为start()不会阻止”。
他是正确的,你也可以在这个最小的例子中调用run()
。但是,我假设您正在启动一个线程,因为您希望它与另一个线程并发运行。在线程上调用run()
被FindBugs标记为可能的错误 - 如果你只是要调用run()
,你可能只想实现Runnable而不是使用Thread。
答案 1 :(得分:6)
在TestThread
函数中,JUnit无法告诉您生成了一个新线程。一旦函数结束(到达最后一行)并且不知道线程,它就会回收它在函数中创建的任何对象。
因此,您可以看到Thread的输出,直到它被杀死。如果您想等待线程完成,可以使用Thread.join
(在致电Thread.start()
之后)使其等待结果或在某个对象上使用wait-notify
。
另外,发现了这个问题:JUnit terminates child threads
答案 2 :(得分:0)
运行测试的父线程可能正在完成。如果可以避免它,那么不要在测试中创建新线程。我将创建一个实现runnable的新类,然后测试该类,我只是在该对象上调用run。您不应该在测试过程中测试线程调度。希望java语言开发团队能够覆盖:)