如果我们创建了一个单例对象来处理Java异常,那么为什么Thread.setDefaultUncaughtExceptionHandler在Java Application Server,Java控制台应用程序中运行正常但不适用于JUnit测试?
例如,以下代码有效:
public class Main extends Object {
public static void main(String[] arguments) {
Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler.getInstance());
double a = 1/0;
}
}
但是这个JUnit测试没有:
public class UncaughtExceptionHandlerTest {
@Test
public void throwException() {
Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler.getInstance());
double a = 1/0;
}
}
但为什么呢?而且,我们如何解决这个问题,自动处理所有JUnit测试异常而不使用每个测试的情绪化尝试?
答案 0 :(得分:3)
JUnit将捕获单元测试对单元测试线程 1 引发的所有意外异常。正常行为是捕获/显示/记录异常作为FAILed测试,然后继续下一个单元测试。
这意味着Java意义上没有“未捕获的异常”,并且不会调用未捕获的异常处理程序。
目前还不完全清楚你要在这里实现什么,但我怀疑答案是实现自定义跑步者:
1 - 如果测试中的代码产生自己的线程,那么JUnit框架无法知道。肯定不能捕获/检测这些线程上未捕获的异常。但是,这似乎不是你在这个问题中所讨论的内容。
主要动机是,例如,如果junit测试失败,则发送电子邮件或执行其他管理任务。如果我有一个全局异常处理程序,我可以这样做,而是为每个测试添加一个catch块。在处理之后,也许我会抛出这个异常并让junit继续前进。
如果这是你想要做的事情,那么你是(IMO)以错误的方式做事。现有的运行程序提供了一个结构化的报告文件,或者一个报告数据结构,可以为您提供所有通过的测试列表,断言失败,异常失败等等。您应该做的是:
优点:
AssertionError
例外...)还有另一种方式。查看JUnitCore
(link)。这允许您为各种测试事件注册一个监听器,然后运行一堆测试或测试套件。
另一点是,您似乎试图复制(部分)持续集成(CI)服务器(如Jenkins)的功能。
然后你问为什么这不起作用:
@Test
public void throwException() {
Thread.setDefaultUncaughtExceptionHandler(/* some handler */));
double a = 1/0;
}
只有在没有其他方法捕获异常时才会调用未捕获的异常处理程序。但是,典型的JUnit测试运行器使用传统的异常处理程序捕获从每个单元测试传播的所有异常。这意味着测试中抛出的ArithmeticException
永远不会到达您的处理程序。
答案 1 :(得分:1)
您的junit @Test
方法引发的异常未被捕获。 JUnit捕获它们并使用它们来使测试失败。
现在,如果您已经启动了一个未在JUnit的try / catch执行中运行的自己的新线程,则抛出的异常将被忽略,您的测试将通过。
想想这个名字...... Thread.setDefaultUncaughtExceptionHandler。这仅涵盖未明确拥有未捕获异常处理程序的线程,然后它不包含调用代码的代码(JUnit等)捕获的异常。
以下是ParentRunner类的相关代码:
protected final void runLeaf(Statement statement,
Description description, RunNotifier notifier) {
EachTestNotifier eachNotifier = new EachTestNotifier(notifier, description);
eachNotifier.fireTestStarted();
try {
statement.evaluate();
} catch (AssumptionViolatedException e) {
eachNotifier.addFailedAssumption(e);
} catch (Throwable e) {
eachNotifier.addFailure(e);
} finally {
eachNotifier.fireTestFinished();
}
答案 2 :(得分:0)
你确定jUnit没有在某个地方捕捉到它吗?方法签名表示它throws Exception
,所以我猜测必须有一个非常广泛的catch
语句上游。