Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Thread.currentThread().setUncaughtExceptionHandler() not working with JUNIT?

Tags:

java

junit

In the example code below, if the testMethod() is run via main() it works as expected but if it is run via JUNIT then MyUncaughtExceptionHandler does not get called.

Is there some explanation for this?

package nz.co.test;

import java.lang.Thread.UncaughtExceptionHandler;

import org.junit.Test;

public class ThreadDemo {

  private void testMethod() {
    Thread.currentThread().setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());

    Object b = null;
    // Cause a NPE
    b.hashCode();
  }

  @Test
  public void testJunit() {
    // Run via JUnit and MyUncaughtExceptionHandler doesn't catch the Exception
    testMethod(); 
  }

  public static void main(String[] args) {
    // Run via main() works as expected
    new ThreadDemo().testMethod();
  }

  static class MyUncaughtExceptionHandler implements UncaughtExceptionHandler {

    @Override
    public void uncaughtException(Thread t, Throwable e) {
      System.out.println("I caught the exception");
    } 
  }
}
like image 760
Rob Bygrave Avatar asked Aug 01 '13 12:08

Rob Bygrave


2 Answers

Obviously, the setUncaughtExceptionHandler sets handler for uncaught exceptions. But JUnit catches all exceptions thrown from test methods.

Anyway, it is weird way to make a unit test. Unit test should test your code, not JVM specification.

I imagine a unit test like this:

public class MyUncaughtExceptionHandlerTest
{
  @Mock Thread thread;
  MyUncaughtExceptionHandler testObject = new MyUncaughtExceptionHandler();

  @Before
  public void setUp()
  {
     MockitoAnnotations.initMocks(this);
  }

  @Test
  public void handleNpeShouldDoOneThing()
  {
    testObject.handleException(thread, new NullPointerException());
    //verify(oneThing)
  }

  @Test
  public void handleOomShouldDoSomethingElse()
  {
    testObject.handleException(thread, new OutOfMemoryError());
    //verify(somethingElse)
  }
}
like image 178
kan Avatar answered Sep 20 '22 17:09

kan


This is because all exception that are thrown in a test are caught and processed by JUnit, so UncaughtExceptionHandler doesnt get any uncaught exceptions. It is done in org.junit.runners.ParentRunners

...
    protected final void runLeaf(Statement statement, Description description,
            RunNotifier notifier) {
        EachTestNotifier eachNotifier = new EachTestNotifier(notifier, description);
        eachNotifier.fireTestStarted();
        try {
            statement.evaluate();   <-- test method execution is called from here
        } catch (AssumptionViolatedException e) {
            eachNotifier.addFailedAssumption(e);
        } catch (Throwable e) {
            eachNotifier.addFailure(e);
        } finally {
            eachNotifier.fireTestFinished();
        }
    }
like image 42
Evgeniy Dorofeev Avatar answered Sep 23 '22 17:09

Evgeniy Dorofeev