无法运行包含Eclipse线程的JUnit测试用例

时间:2009-04-17 12:59:43

标签: eclipse junit

我正在运行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);
  }
}

3 个答案:

答案 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++;
    }

}