Java 有没有办法强迫JUnit在任何未检查的异常上失败,即使被吞没

Java 有没有办法强迫JUnit在任何未检查的异常上失败,即使被吞没,java,unit-testing,junit,swallowed-exceptions,Java,Unit Testing,Junit,Swallowed Exceptions,我正在使用JUnit为没有单元测试的遗留代码编写一些更高级别的测试 这段代码中的大部分“吞咽”了各种未经检查的异常,如NullPointerException(例如,通过打印堆栈跟踪并返回null)。因此,即使在较低级别的代码中的各个点上存在一连串的灾难,单元测试也可以通过 有没有办法让测试在第一个未检查的异常上失败,即使它们被吞没了 我能想到的唯一替代方法是编写一个自定义JUnit包装器,重定向System.err,然后分析异常的输出。如果在IDE的调试器中执行测试,您可以配置IDE在抛出异常

我正在使用JUnit为没有单元测试的遗留代码编写一些更高级别的测试

这段代码中的大部分“吞咽”了各种未经检查的异常,如NullPointerException(例如,通过打印堆栈跟踪并返回null)。因此,即使在较低级别的代码中的各个点上存在一连串的灾难,单元测试也可以通过

有没有办法让测试在第一个未检查的异常上失败,即使它们被吞没了


我能想到的唯一替代方法是编写一个自定义JUnit包装器,重定向System.err,然后分析异常的输出。

如果在IDE的调试器中执行测试,您可以配置IDE在抛出异常时中断。

由于缺乏具体的解决方案,我的回答相当笼统:

当您在对遗留系统进行错误修复时遇到此类代码气味(例如,swalling异常)时,最好一步一步(逐类)清除它们。代码质量工具(例如Findbugs、PMD、Checkstyle甚至Sonar quality Server)可以帮助您找到这些东西


自动“捕获”被吞没的异常的一种方法是使用AspectJ编译器。当违反某些代码约定时,可以声明方面以在IDE中生成编译时错误。或者,您可以在运行时编织测试中的类,并让AspectJ重新显示此类异常,以便JUnit运行程序可以记录这些异常。

可以使用修改字节码的模拟框架或AOP框架模拟您想要捕获的异常。我想您可以修改构造函数来抛出更致命的异常,或者在测试代码中设置一些标志。

我相信异常只是SDK库中的一个标准类

如果您提取它,修改它,并将它放在SDK之前的类路径上,我认为它应该替换SDK中的一个(如果没有,您可以将“新”异常放回SDK jar中)

无论如何,您的新异常可以设置测试框架可以读取的静态值


可能不是最优雅的解决方案,但它不需要任何“魔法”

我会尝试使用AOP抛出失败。类似的东西应该可以工作(注意,我还没有测试过它,很明显,您需要有AspectJ设置才能使用AOP注释)

}
}

也许您可以粘贴要测试的代码。很可能您必须使用一些“重新映射”测试框架,如powermock或jmockit来操纵JVM中的类加载器操纵。但是一个被测试类的样本将有助于确定所需的方法。

No,如果在到达JUnit代码之前就被吞没,JUnit如何知道异常?但也许您不应该依赖于遗留代码中发生的任何事情,只需检查代码是否正确即可。毕竟,当出现影响代码结果的错误时,测试应该失败。@FRotthowe:我正在使用JUnit为遗留代码的现有组件编写回归测试和包装测试。我没有太多自己的代码。问题是我想捕获这些内部故障,尤其是在人们维护内部代码时。+1-PMD已经有了一个查找空捕获块的规则。扩展它来制定规则来寻找其他在异常处理中失败的常见方法可能并不难,因为代码在java中。程序包,JDK有一些安全机制来防止您必须解决的那种修补。@Yishai奇怪,我知道有人这样做,但没有深入研究他们所做的工作的机制。我得进一步调查。。。(看了之后,这一页似乎不同意:)是的,引导类路径是基本思想,但这意味着一个单独制作和编译的类包装在一个单独的jar中,或者其他一些别出心裁的东西来分隔这些实现,然后你就不能让这个类与任何其他类交互(比如JUnit类)你的测试必须调用它,而不是相反。这是可行的,只是太容易了。
public class ClassUnderTest
{
   private static Boolean exceptionThrown;


   @Before
   public void resetExceptionFlag()
   {
      ClassUnderTest.exceptionThrown = false;
   }

   @Test
   public void myTestMethod()
   {

      //....
      // My Test Exception Code
      //....

      assertFalse(ClassUnderTest.exceptionThrown);
   }

   @Aspect
   static class TestAspects
   {
      @Pointcut("handler(Exception)")
      public void intereceptAllExceptions(){}

      //This is Fully Qualified because of the conflict with the junit Before annotation above
      @org.aspectj.lang.annotation.Before("intereceptAllExceptions()")
      public void flagExceptionThrown()
      {
         ClassUnderTest.exceptionThrown = true;

  }