26

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();
        }
    }
}
Michal Kordas
  • 10,475
  • 7
  • 58
  • 103
HipsterZipster
  • 1,326
  • 1
  • 14
  • 34
  • One way could be found here by customizing the ThreadFactory https://stackoverflow.com/questions/9280846/how-to-interrupt-executorservices-threads/50879442#50879442 – wtsolid Jun 15 '18 at 16:28

7 Answers7

33

Right before invoking addMessage(), call Thread.currentThread().interrupt(). This will set the "interrupt" status flag on the thread.

If the interrupted status is set when the call to put() is made on a LinkedBlockingQueue, an InterruptedException will be raised, even if no waiting is required for the put (the lock is un-contended).

By the way, some efforts to reach 100% coverage are counter-productive and can actually degrade the quality of code.

erickson
  • 265,237
  • 58
  • 395
  • 493
  • 2
    +1, this is true. Aim for 80-85 and you'll avoid all the problems like this and still keep your code pretty pristine. – BjornS Sep 14 '10 at 07:58
  • 2
    This is quite a brutal solution and could have unexpected side-effects. For instance, I found that calling Thread.currentThread().interrupt() in one test method would affect all test methods in the same class, causing all the other tests to fail. I also found that adding this to any test class would cause Sonar to report 0% unit test coverage (haven't discovered why). – RCross Mar 21 '13 at 10:25
  • Yes, you'd have to be careful where you used it, making sure that the interrupt status will be cleared (as it is here) and that there is no intervening check of the status between your setting and your test's checking of it. – erickson Mar 21 '13 at 16:27
  • @RCross I just ran into the code coverage issue too, via IntelliJ. It apparently hates it when you interrupt the thread. – Alex Moore Oct 25 '16 at 04:51
16

Use a mocking library like Easymock and inject a mock LinkedBlockingQueue

i.e.

@Test(expected=InterruptedException.class)
public void testInterruptedException() {
    LinkedBlockingQueue queue = EasyMock.createMock(LinkedBlockingQueue.class);
    ExampleMessage message = new ExampleMessage();
    queue.put(message);
    EasyMock.expectLastCall.andThrow(new InterruptedException()); 
    replay(queue);
    someObject.setQueue(queue);
    someObject.addMessage(msg);
}
timbre timbre
  • 12,648
  • 10
  • 46
  • 77
Peter Tillemans
  • 34,983
  • 11
  • 83
  • 114
9

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.

ixi
  • 441
  • 5
  • 10
1

Another option is to delegate dealing with InterruptedException to Guava's Uninterruptibles, so you don't need to write and test your custom code for it:

import static com.google.common.util.concurrent.Uninterruptibles.putUninterruptibly;

private final LinkedBlockingQueue<ExampleMessage> queue;  

public void addMessage(ExampleMessage message) {  
    putUninterruptibly(queue, message);
}
Michal Kordas
  • 10,475
  • 7
  • 58
  • 103
0

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.

wtsolid
  • 41
  • 3
0

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();
kap
  • 1,456
  • 2
  • 19
  • 24
0

To expand on @ixi's answer here's a code example. The purpose of the test is to ensure correct implementation of the InterruptedException handling on code that is not able to rethrow InterruptedException.

This is assuming that the code in the OP was done correctly. In which case the corrected code would be:

@RequiredArgsConstructor
@Slf4j
class SomeClass {
  private final LinkedBlockingQueue<ExampleMessage> m_Queue;  

  public void addMessage(ExampleMessage hm) {  
    if (hm!=null){
      try {
        m_Queue.put(hm);
      } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        log.warn("Thread interrupted", e);
      }
    }
  }
}

The test would be

@Test
public void testInterruptedException() throws Exception {
  @SuppressWarnings("unchecked")
  final LinkedBlockingQueue<ExampleMessage> queue = 
    spy(LinkedBlockingQueue.class);

  doThrow(InterruptedException.class)
    .when(queue)
    .put(any(ExampleMessage.class));

  queue.put(mock(ExampleMessage.class));
  
  assertThat(Thread.interrupted())
   .isTrue();

}

As I noted earlier, a test like this guards your implementation so that you ensure correct implementation of the InterruptedException handling.

Archimedes Trajano
  • 35,625
  • 19
  • 175
  • 265