Back to Top

Saturday, October 27, 2012

Helper for testing multi-threaded programs in Java

This post was originally published on the Transylvania JUG blog.

Testing multi-threaded code is hard. The main problem is that you invoke your assertions either too soon (and they fail for no good reason) or too late (in which case the test runs for a long time, frustrating you). A possible solution is to declare an interface like the following:

interface ActivityWatcher {
 void before();
 void after(); 
 void await(long time, TimeUnit timeUnit) throws InterruptedException, TimeoutException;
}


It is intended to be used as follows:
  • “before” is called before the asynchronous task is delegated to an execution mechanism (threadpool, fork-join framework, etc) and it increments an internal counter.
  • “after is called after the asynchronous task has completed and it decrements the counter.
  • “await” waits for the counter to become zero
The net result is that when the counter is zero, all your asynchronous tasks have executed and you can run your assertions. See the example code. A couple more considerations:
  • There should be a single ActivityWatcher per test (injected trough constructors or a dependency injection framework)
  • In production code you will use a dummy/noop implementation which removes any overhead.
  • This only works for situations where the asynchronous are kicked of immediately. Ie. it doesn’t work for situations where we have periodically executing tasks (like every 5 seconds) and we would want to wait for the 7th tasks to be executed for example.
One thing the above code doesn’t do is collecting exceptions: if the exceptions happen on different threads than the one executing the testrunner, they will just die and the testrunner will happily report that the tests passs. You can work around this in two ways:
  • use the default UncaughtExceptionHandler to capture all exceptions and rethrow them in the testrunner if they arrise (not so nice because it introduces global state – you can’t have two such tests running in parallel for example)
  • Extend activity watcher and code calling activity watcher such that it has a “collect(Throwable)” method which gets called with the uncaught exceptions and “await” rethrows them.
Implementing this is left as an exercise to the reader :-).;-)

0 comments:

Post a Comment

You can use some HTML tags, such as <b>, <i>, <a>. Comments are moderated, so there will be a delay until the comment appears. However if you comment, I follow.