Testing Asynchronous Code in Java with CountDownLatch

Asynchronous Event driven applications are becoming ever more common, and testing the correctness of these applications can be tricky. However, there are some techniques and tools available to aid testing asynchronous code – one such tool is a CountDownLatch.

Executing Concurrent Tasks

Suppose we have an application that runs simple tasks. These tasks can take varying amount of time to finish. Upon the completion of a task, a task can be marked as executed.

The Tasks are run by a TaskRunner object, which uses an Executor Service to run tasks concurrently:

Basic Test Case

If we have to write a very basic test case for the task runner, it may look like:

In the above test we had to a Thread.sleep() of 2 seconds because the tasks may not have finished before we reach assert statements.  However, the tasks may take more or less than 2 seconds to finish.

There are at least two problems with this approach:

  • The test is unreliable, as running the tests on a faster or slower machine or build agent influences the result of the test.
  • These kind of tests also make the build slower when unit tests are run as part of the build. This goes against the principles of “Continuous Integration”

We can circumvent these concerns with a CountDownLatch

What is a CountDownLatch?

A CountDownLatch is a construct that allows one or more threads to wait until a set of operations being performed in other thread completes.

  • The latch is initialised with a Count, a positive integer e.g. 2
  • The thread that calls latch.await() will block until the Count reaches to Zero
  • All other threads are required to decrement the Count by calling latch.countDown()
  • Once the Count reaches Zero, the awaiting thread resumes execution

tasksOnce a latch reaches Zero, it can no longer be used, a brand new latch needs to be created. However, a CyclicBarrier may be more suited for such requirements.The following is a simple usecase of how to use a CountDownLatch:

Better Tests using Latch

The TestRunner test we discussed previously using Thread.sleep(…) can be written using a CountDownLatch. Note how the test calls latch.await() to wait for all tasks to finish before it can verify the assertions.

This gist can be found here: https://gist.github.com/openraz/21f6bae97795ea145ea0

If a Task doesn’t finish due to a bug in our TestRunner implementation, then test may forever block. Thus, its a good idea to impose a timeout on our tests either by introducing timeout parameter in the @Test annotation @Test(timeout=2000) or simply specifying a timeout in the await   latch.await(2, TimeUnit.SECONDS);

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">