Java 如何在junit测试中捕获所有未捕获的异常?

Java 如何在junit测试中捕获所有未捕获的异常?,java,junit,exception-handling,junit4,Java,Junit,Exception Handling,Junit4,如果我们创建了一个singleton对象来处理Java异常,为什么Thread.setDefaultUncaughtExceptionHandler在Java应用程序服务器、Java控制台应用程序中运行正常,但在JUnit测试中不起作用 例如,以下代码起作用: public class Main extends Object { public static void main(String[] arguments) { Thread.setDefaultUncaught

如果我们创建了一个singleton对象来处理Java异常,为什么Thread.setDefaultUncaughtExceptionHandler在Java应用程序服务器、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测试异常而不在每个测试中使用moody try catch?

您确定JUnit没有在某个地方捕获它吗?方法签名表示它
抛出异常
,因此我猜上游必须有一个相当广泛的
catch
语句。

JUnit将捕获单元测试线程1上的单元测试抛出的所有意外异常。正常行为是将异常捕获/显示/记录为失败的测试,然后继续进行下一个单元测试

这意味着Java意义上不存在“未捕获异常”,并且不会调用您的未捕获异常处理程序

现在还不完全清楚您在这里想要实现什么,但我怀疑答案应该是实现一个定制的运行程序:


1-如果测试中的代码产生了自己的线程,JUnit框架无法知道。它当然不能捕获/检测那些线程上的未捕获异常。然而,这似乎不是你在这个问题上所说的


例如,主要动机是,如果junit测试失败,发送电子邮件或执行其他管理任务。如果我有一个全局异常处理程序,我可以这样做,而是在每个测试中放置一个catch块。在处理之后,也许我会抛出这个异常,让junit继续处理它

好吧,如果这就是你想要做的,那么你(依我看)做得不对。现有的运行程序提供结构化的报告文件或报告数据结构,可以为您提供所有通过的测试、断言失败的测试、异常失败的测试等的列表。您应该做的是:

  • 选择合适的跑步者
  • 分析其产出
  • 如果出现符合您标准的错误,请发送一封电子邮件(或其他任何邮件)
优点:

  • 更少的努力
  • 您处理所有错误,而不仅仅是未捕获的异常(尽管实际上断言失败表现为
    AssertionError
    exceptions…)
  • 你不会在每一次失败的测试上都发垃圾邮件
还有另一种方法。看一下JUnitCore。这允许您为各种测试事件注册一个侦听器,然后运行一组测试或测试套件

另一点是,您似乎试图复制(部分)连续集成(CI)服务器(如Jenkins)的功能


然后你问为什么这不起作用:

@Test
public void throwException() {
    Thread.setDefaultUncaughtExceptionHandler(/* some handler */));
    double a = 1/0;
}

未捕获的异常处理程序只有在没有其他内容捕获该异常时才被调用。但是,典型的JUnit测试运行程序使用常规异常处理程序捕获从每个单元测试传播的所有异常。这意味着测试中抛出的
算术异常
永远不会到达处理程序。

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();
    }

说得好——这就是我想要表达的;)我来看看。我把动机放在上面。我会让junit执行它的正常任务,但是,我想拦截它并执行我的一些任务。在这个链接上,我正在做的应该是可能的。但是,我不希望使用与ExceptionHandler类相同的测试类来代替这个实现。但是我不明白为什么上面的代码不起作用。嗯。。。JUnit肯定不会捕获所有可能抛出的异常;如果您是在代码生成的线程上运行的,那么它们是否崩溃仍取决于您的注意。JUnit只负责运行
@Test
注释方法的线程。不理解下一票。例如,主要动机是,如果junit测试失败,发送电子邮件或执行其他管理任务。如果我有一个全局异常处理程序,我可以这样做,而是在每个测试中放置一个catch块。在处理之后,也许我会抛出这个异常,让junit继续处理它。抛出是在我的测试中进行的。这是不必要的,因为这是一个运行时异常。如果捕获到异常,那么在调试模式下,它将在UncaughtExceptionHandler类的断点处停止,就像在Java控制台应用程序中一样。仅部分正确。JUnit可以捕获在子线程中抛出的异常,并且将使当前运行的测试用例失败,即使它没有生成该线程。不确定您所说的JUnit版本,但JUnit 4至少您的注释是不正确的。异常打印,测试通过。