Java/Maven, Programming

Testing threads with JUnit

Problem
Sometimes there is a need to test a simple piece of multi-threaded code. For example, how will your code behave, when two threads read and then modify one of the variables? Well, if you know your threads you can devise and code the scenario, so that thread access is exactly right. For example, by using a mutex or semaphore. But how do you assert that your test succeeds? I mean besides sitting next to it with a debug session and checking things on every step.

JUnit is a very nice framework, but it does not handle assertions within other threads as well as one would hope it could.

Solution
I will use JUnit 4.0, but this applies to earlier versions as well.

In the sample below we have two test cases, testCaseNaive() will try to do the thing that should work out of the box. However, as far as JUnit is concerned the test succeeds with flashing lights and shooting ribbons. The second test case, testCase2Threads(), uses a somewhat hackish trick. And this trick does involve you creating the two runnables right here in the test.

The idea is quite simple, assertions in JUnit propagate up through the stack by throwing an exception, which is then caught by the test runner. If we get to execute the last statement in the thread as planned – all is well, no assertions were violated, if not – something has gone wrong. And in the case of a fail we rely on the test runner to print out the exception.

// TestMyClass.java

import java.util.ArrayList;
import java.util.Vector;
import junit.framework.Assert;
import org.junit.Test;

public class TestMyClass {

	@Test public void testCaseNaive() throws InterruptedException{
		Runnable runnable1 = new Runnable() {
			@Override public void run() {
				Assert.fail();
			}			
		};
		Thread t1 = new Thread( runnable1 );
		t1.start();
		t1.join();
	}
	
	@Test public void testCase2Threads() throws InterruptedException {
		final ArrayList< Integer > threadsCompleted = new ArrayList< Integer >();
		Runnable runnable1 = new Runnable() {
			@Override public void run() {
				Assert.fail();
				threadsCompleted.add(1);
			}
		};
		
		Runnable runnable2 = new Runnable() {
			@Override public void run() {
				Assert.assertTrue( true );
				threadsCompleted.add(2);
			}
		};
		
		Thread t1 = new Thread( runnable1 );
		Thread t2 = new Thread( runnable2 );
		
		t1.start();
		t2.start();
		t1.join();
		t2.join();
		
		System.out.println( "Threads completed: " + threadsCompleted );
		Assert.assertEquals(2, threadsCompleted.size());
	}
}
// testCaseNaive() passes, but the output still contains this
Exception in thread "Thread-0" junit.framework.AssertionFailedError: null
	at junit.framework.Assert.fail(Assert.java:47)
	at junit.framework.Assert.fail(Assert.java:53)
	at TestMyClass$1.run(TestMyClass.java:13)
	at java.lang.Thread.run(Unknown Source)
// testCase2Threads() fails and the output is:
Exception in thread "Thread-1" junit.framework.AssertionFailedError: null
	at junit.framework.Assert.fail(Assert.java:47)
	at junit.framework.Assert.fail(Assert.java:53)
	at TestMyClass$2.run(TestMyClass.java:25)
	at java.lang.Thread.run(Unknown Source)
Threads completed: [2]

Generally speaking, I have not found a nice way to assert fine detail inside a thread. The exceptions are cut off from the main thread and therefore never reach the runner. So the only way to look at these tests is to test the side effects after the test is complete or in the middle of the execution, if you can stop your threads reliably.

Standard

5 thoughts on “Testing threads with JUnit

  1. Marc says:

    Interesting. But, I don’t see why the second thread is needed ? Why not just check if the threadsCompleted is 1 ? See code below :

    @Test
    public void testCase2Threads() throws InterruptedException {

    final ArrayList threadsCompleted = new ArrayList();

    Runnable runnable1 = new Runnable() {

    @Override public void run() {
    Assert.fail();
    threadsCompleted.add(1);
    }
    };

    Thread t1 = new Thread( runnable1 );

    t1.start();

    System.out.println( “Threads completed: ” + threadsCompleted );
    Assert.assertEquals(1, threadsCompleted.size());
    }

    • Andrej Kazakov says:

      True, but 2 threads are always more interesting. In most cases, where one will use this idea, there will be more than 1 thread :)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s