我正在运行Eclipse 3.4.1中的JUnit测试用例。这个测试用例创建了一个类,它启动一个线程来做一些事情。当测试方法结束时,似乎Eclipse强行关闭了线程。
如果我从命令行运行相同的测试,则线程正常运行。
不知怎的,我不记得之前遇到过Eclipse的问题。这是Eclipse中始终存在的东西还是在3.4.x中添加它?
以下是一个例子:
当我从Eclipse运行此测试时,我得到了一些cnt的打印件(直到大约1800),然后测试用例被自动终止。但是,如果我运行启动JUnit的TestRunner的main方法,那么线程将无限制地计算。
import junit.framework.TestCase;
import junit.textui.TestRunner;
/**
* This class shows that Eclipses JUnit test case runner will forcibly
* terminate all running threads
*
* @author pshah
*
*/
public class ThreadTest extends TestCase {
static Runnable run = new Runnable() {
public void run() {
int cnt = 0;
while(true) System.out.println(cnt++);
}
};
public void testThread() {
Thread t = new Thread(run);
t.start();
}
public static void main(String args[]) {
TestRunner runner = new TestRunner();
runner.run(ThreadTest.class);
}
}
答案 0 :(得分:3)
我将你的代码改编为JUnit NG并且结果相同:线程被杀死了。
public class ThreadTest {
static Runnable run = new Runnable() {
public void run() {
int cnt = 0;
while (true)
System.out.println(cnt++);
}
};
@Test
public void threadRun() {
Thread t = new Thread(run);
t.start();
assertEquals("RUNNABLE", t.getState().toString());
}
}
如果我使用(在我的情况4.3.1)JUnit的罐子从插件的Eclipe夹经由命令行来执行测试,它有像在Eclipse执行它(这是逻辑:))相同的行为。
我在命令行中测试了JUnit 4.6(刚刚下载),它也在短时间内停止了!它与Eclipse中的行为完全相同
我发现,如果最后一条指令完成,它就会被杀死。如果你考虑JUnit是如何工作的,这是合乎逻辑的:
对于每个测试,都会创建一个新对象。如果测试结束,它就会被杀死。属于这个测试的一切都被杀死了
这意味着,必须停止每个线程。
JUnit正确处理这种情况。单元测试必须隔离且易于执行。因此,如果到达测试结束,它必须结束所有线程。
你可能等待,直到测试结束,然后执行你的assertXXX
指令。这将是测试线程的正确方法
但要小心:它可能会扼杀你的执行时间!
答案 1 :(得分:1)
我相信这种修改会产生单元测试各种线程场景所需的结果。
(抱歉,如果格式不稳定)
public class ThreadTest {
static Runnable run = new Runnable() {
public void run() {
int cnt = 0;
while (true)
System.out.println(cnt++);
}
};
@Test
public void threadRun() {
Thread t = new Thread(run);
t.start();
//Run the thread, t, for 30 seconds total.
//Assert the thread's state is RUNNABLE, once per second
for(int i=0;i<30;i++){
assertEquals("RUNNABLE", t.getState().toString());
try {
Thread.sleep(1000);//1 second sleep
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Done with my thread unit test.");
}
}
答案 2 :(得分:1)
这有效,但你必须为你的线程命名或找到另一种方式来引用它。
protected boolean monitorSecondaryThread(String threadName, StringBuilder errorMessage, boolean ignoreFailSafe) {
int NUM_THREADS_BESIDES_SECONDARY_THREAD = 2;
int MAX_WAIT_TIME = 10000;
MyUncaughtExceptionHandler meh = new MyUncaughtExceptionHandler();
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
for (Thread t : threadSet) {
t.setUncaughtExceptionHandler(meh);
}
Date start = Calendar.getInstance().getTime();
boolean stillAlive = true;
while (stillAlive) {
for (Thread t : threadSet) {
if (t.getName().equalsIgnoreCase(threadName) && !t.isAlive()) {
stillAlive = false;
}
}
Date end = Calendar.getInstance().getTime();
if (!ignoreFailSafe && (end.getTime() - start.getTime() > MAX_WAIT_TIME || Thread.activeCount() <= NUM_THREADS_BESIDES_SECONDARY_THREAD)) {
System.out.println("Oops, flawed thread monitor.");
stillAlive = false;
}
}
if (meh.errorCount > 0) {
System.out.println(meh.error);
errorMessage.append(meh.error);
return false;
}
return true;
}
private class MyUncaughtExceptionHandler implements UncaughtExceptionHandler {
public int errorCount = 0;
public String error = "";
@Override
public void uncaughtException(Thread t, Throwable e) {
ByteArrayOutputStream bs = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(bs);
e.printStackTrace(ps);
error = bs.toString();
errorCount++;
}
}