在下面的示例代码中,如果testMethod()是通过main()运行的,它按预期工作,但如果它是通过JUNIT运行的话,则不会调用MyUncaughtExceptionHandler。
对此有一些解释吗?
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");
}
}
}
答案 0 :(得分:7)
显然,setUncaughtExceptionHandler
设置了未捕获异常的处理程序。但是JUnit捕获了从测试方法抛出的所有异常。
无论如何,进行单元测试是一种奇怪的方式。单元测试应该测试您的代码,而不是JVM规范。
我想像这样的单元测试:
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)
}
}
答案 1 :(得分:6)
这是因为JUnit捕获并处理了测试中抛出的所有异常,因此UncaughtExceptionHandler不会获取任何未捕获的异常。它在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();
}
}