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");
    } 
  }
}
                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)
  }
}
                        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();
        }
    }
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With