Eclipse and Asynchronous Unit Testing

I’ve been retro-fitting hundreds of JUnit tests to Archi‘s code base. It’s a Zen meditation, as the process of devising the unit tests ensures that I re-engage with the code, clean things up, refactor here and there, and finally understand what that nifty algorithm does that I wrote 3 years ago. Like children not eating their greens, no-one wants to write unit tests. But it’s a valuable thing to do and rewarding, especially when you see the green bar in Eclipse:

Testing

Perhaps the process of testing and being rewarded by the green bar is an example of “gamification”? Maybe, but I’m not interested in vacuous neologisms, I’d rather just get stuff done.

Some tests that I wrote were failing. The code that these tests was calling depended on events occurring in the UI of the application, such as an editor window opening. The tests were finishing before the editor window opened. Not sure what to do about this I went for a jog to have a think. And then I remembered that I already had the answer in one of my own posts, Xcode and Asynchronous Unit Testing. This has turned out to be quite a popular post in the Xcode and Objective-C community, solving a common problem. So I wondered if Eclipse would be happy with a similar pattern. I’m never sure what’s going to happen when I start playing with threads and dispatch queues.

Here’s my solution, an abstract Java class called “AsyncTestRunner”.

public abstract class AsyncTestRunner implements Runnable {

    boolean waiting = true;

    @Override
    public void run() {
        stop();
    }

    public void start() {
        Display.getCurrent().asyncExec(this);

        while(waiting) {
            if(!Display.getCurrent().readAndDispatch()) {
                Display.getCurrent().sleep();
            }
        }
    }

    public void stop() {
        waiting = false;
    }

}

This class implements Runnable which has one method, run(). This run() method will be called by the current Display instance asynchronously in this line:

Display.getCurrent().asyncExec(this);

Meanwhile the read and dispatch process will go off and do its thing in the event loop:

while(waiting) {
    if(!Display.getCurrent().readAndDispatch()) {
        Display.getCurrent().sleep();
    }
}

This ensures that UI tasks can be completed.

Here’s an example of how we use it:

AsyncTestRunner runner = new AsyncTestRunner() {
    @Override
    public void run() {
        super();

        // Run some code that needs testing in the UI
        Object someThing = ...;
        assertNotNull(someThing);
    }
};

runner.start();

Here, we create a new anonymous instance of AsyncTestRunner and implement run() with the testing code and then call its start() method. Be sure to call super() in the run method to invoke stop() which sets a boolean flag to false which breaks the event loop in the start() method.

The class may seem verbose with its stop() method, you could simply directly set the waiting flag to false, but I wrote it like this so it can be sub-classed and to make it obvious what’s going on. I also like the idea of a run() method consisting of one stop() method.

public void run() {
    stop();
}

Very Zen.

So far it works in both Eclipse 3.8.2 and Eclipse 4.4. I may find a gotcha further down the line, and I may refine the class in the future, but so far it’s looking good. If it can be improved I’d be glad to hear about it.

Begin typing your search term above and press enter to search. Press ESC to cancel.