代码之家  ›  专栏  ›  技术社区  ›  Parag

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

  •  3
  • Parag  · 技术社区  · 16 年前

    我正在运行Eclipse3.4.1中的JUnit测试用例。这个测试用例创建了一个类,它启动一个线程来做一些事情。当测试方法结束时,Eclipse似乎正在强制关闭线程。

    如果我从命令行运行相同的测试,那么线程就可以正常运行。

    不知怎么的,我不记得以前在Eclipse中遇到过这样的问题。这是Eclipse中一直存在的东西还是在3.4.x中添加的?

    下面是一个例子:

    当我从Eclipse运行这个测试时,我得到了几个CNT的打印件(直到1800年左右),然后测试用例自动终止。但是,如果我运行主方法(它启动了JUnit的testreunner),那么线程的计数将非常精确。

    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 回复  |  直到 13 年前
        1
  •  3
  •   guerda    16 年前

    我将您的代码修改为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());
      }
    
    }
    

    如果我使用eclipe plugin文件夹中的junit jar(在我的例子中是4.3.1)通过命令行执行测试,它的行为与在eclipse中执行测试的行为相同(逻辑上是:)。

    我在命令行中测试了Junit4.6(刚刚下载),它也在短时间后停止了!就像在Eclipse中一样


    我发现,如果最后一个指令完成了,它就会被杀死。如果考虑到JUnit的工作方式,这是合乎逻辑的:
    对于每个测试,都会创建一个新对象。如果测试结束,它就死了。所有属于这个测试的东西都被杀死了。
    这意味着,必须停止所有线程。

    JUnit正确处理这种情况。单元测试必须是隔离的,并且易于执行。因此,如果测试结束,它必须结束所有线程。

    可以 等待,直到测试完成,然后执行 assertXXX 指令。这是测试线程的正确方法。
    但要小心:它可能会杀死你的执行时间!

        2
  •  1
  •   Yishai    15 年前

    我相信这种修改将产生单元测试各种线程场景所需的结果。

    (如果格式不正确,对不起)

    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.");
     }
    }
    
        3
  •  1
  •   Andy    13 年前

    这是可行的,但你必须命名你的线程或找到另一种方法来引用它。

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