How to write unit test for "InterruptedException"

Viewed 26397

In attempts of 100% code coverage, I came across a situation where I need to unit test block of code that catches an InterruptedException. How does one correctly unit test this? (JUnit 4 syntax please)

private final LinkedBlockingQueue<ExampleMessage> m_Queue;  

public void addMessage(ExampleMessage hm) {  
    if( hm!=null){
        try {
            m_Queue.put(hm);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
6 Answers

As stated above just make use Thread.currentThread().interrupt() if you caught InterruptedException and isn't going to rethrow it.

As for the unit testing. Test this way: Assertions.assertThat(Thread.interrupted()).isTrue();. It both checks that the thread was interrupted and clears the interruption flag so that it won't break other test, code coverage or anything below.

One proper way could be customizing/injecting the ThreadFactory for the executorservice and from within the thread factory, you got the handle of the thread created, then you can schedule some task to interrupt the thread being interested.

Demo code part for the overwrited method "newThread" in ThreadFactory:

ThreadFactory customThreadfactory new ThreadFactory() {

            public Thread newThread(Runnable runnable) {
                final Thread thread = new Thread(runnable);
                if (namePrefix != null) {
                    thread.setName(namePrefix + "-" + count.getAndIncrement());
                }
                if (daemon != null) {
                    thread.setDaemon(daemon);
                }
                if (priority != null) {
                    thread.setPriority(priority);
                }

                scheduledExecutorService.schedule(new Callable<String>() {
                    public String call() throws Exception {
                        System.out.println("Executed!");
                        thread.interrupt();
                        return "Called!";

                    }
                },
                5,
                TimeUnit.SECONDS);

                return thread;
            }
        }

Then you can use below to construct your executorservice instance:

ExecutorService executorService = Executors.newFixedThreadPool(3,
        customThreadfactory);

Then after 5 seconds, an interrupt signal will be sent to the threads in a way each thread will be interrupted once in executorservice.

The example code in the question may be testable by calling Thread.currentThread().interrupt(). However, besides the mentioned problems various methods reset the interrupted flag. An extensive list is for example here: https://stackoverflow.com/a/12339487/2952093. There may be other methods as well.

Assuming waiting implemented as follows should be tested:

try {
  TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException ex) {
    // Set the interrupt flag, this is best practice for library code
    Thread.currentThread().interrupt();
    throw new RuntimeException(ex);
}

A call to Thread.sleep itself clears the interrupted flag, so it cannot be set in advance. It can be tested using its own test thread as follows:

AtomicBoolean threadInterrupted = new AtomicBoolean(false);
Runnable toBeInterrupted = () -> {
    try {
        methodUnderTest();
    } catch (RuntimeException unused) {
        // Expected exception
        threadInterrupted.set(true);
    }
};

// Execute the in an operation test thread
Thread testThread = new Thread(toBeInterrupted);
testThread.start();

// When the test thread is waiting, interrupt
while (!threadInterrupted.get()) {
    if (testThread.getState() == Thread.State.TIMED_WAITING) {
        testThread.interrupt();
    }
}

// Assert that the interrupted state is re-set after catching the exception
// Must be happening before thread is joined, as this will clear the flag
assertThat(testThread.isInterrupted(), is(true));
testThread.join();
Related