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