Friday, April 17, 2009

Eclipse's JUnit test runner forcibly terminates threads

Today I was writing a unit test which instantiated a class, which started a thread to do some stuff. I was hoping to test the side effect of that thread. However, to my surprise, I realized that Eclipse would forcibly terminate the test after the test method exited, even before the thread completed it's work.

I wrote a simple test to show this.


import com.sun.org.apache.xpath.internal.operations.And;
import junit.framework.TestCase;
import junit.textui.TestRunner;

/**
* This class shows that Eclipse's JUnit test case runner will forcibly terminate
* the JVM and all running threads
*/
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);
}
}


This class basically starts a Thread which prints an increasing count in an infinite while loop. When I run this class as a unit test from Eclipse, the count is printed till about 1890 and then the thread terminates. However, when I run the main method (which runs the unit test using JUnit's TestRunner) then the test runs as expected.

I actually added the main method to eliminate the doubt that JUnit might be terminating the thread. I know this is unlikely, but I just wanted to be sure.

I just find it strange that this is the first time I have run into this issue. Especially after working for so many years with Eclipse. I find it hard to believe that I have never written a test case which started a thread and had to wait for it to do something. Or maybe this is a bug in the latest version of Eclipse (3.4.2).

For now I have worked around this issue by putting the main thread to sleep till a property indicating that that the thread has completed it's work is set.

4 comments:

Anonymous said...

you can wait for some thread using Thread#join method, if you can get to the reference of that thread

Parag said...

Hi,

Yes, that would work. But if a test starts multiple threads, then I cannot join on a particular thread, since I do not know if it will be the last to end.

Having the threads tell the main process that they have ended (by setting a variable value) and having the main process sleep till it knows that all threads have terminated, seems to be one approach which will scale up.

izeye said...

I guess this comment is quite late to be any help.

But I found the following code in org.eclipse.jdt.internal.junit.runner.RemoteTestRunner:

/**
* The main entry point.
*
* @param args Parameters:
* -classnames: the name of the test suite class
* -testfilename: the name of a file containing classnames of test suites
* -test: the test method name (format classname testname)
* -host: the host to connect to default local host
* -port: the port to connect to, mandatory argument
* -keepalive: keep the process alive after a test run
*
*/
public static void main(String[] args) {
try {
RemoteTestRunner testRunServer= new RemoteTestRunner();
testRunServer.init(args);
testRunServer.run();
} catch (Throwable e) {
e.printStackTrace(); // don't allow System.exit(0) to swallow exceptions
} finally {
// fix for 14434
System.exit(0);
}
}

As you can see, after test it calls System.exit(0).

That's why all created threads die.

You can use '-keepalive' option for the threads not to be killed :-)

Parag Shah said...

Thanks izeye, your answer was helpful.