【问题标题】:Is there a way to force JUnit to fail on ANY unchecked exception, even if swallowed有没有办法强制 JUnit 在任何未经检查的异常上失败,即使被吞下
【发布时间】:2010-05-06 17:13:43
【问题描述】:

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

大部分代码“吞下”了各种未经检查的异常,如 NullPointerExceptions(例如,仅打印堆栈跟踪并返回 null)。因此,即使在底层代码的各个点发生级联灾难,单元测试也可以通过。

有什么方法可以让第一个未经检查的异常测试失败,即使它们被吞没了?

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

【问题讨论】:

  • 不,如果异常在到达 JUnit 代码之前被吞掉,JUnit 怎么知道?但也许您不应该依赖遗留代码中发生的任何事情,而只需检查您的代码是否正确。毕竟,当出现影响代码结果的问题时,您的测试应该会失败。
  • @FRotthowe:我正在使用 JUnit 为遗留代码的现有组件编写回归测试和包装器测试。我没有太多自己的代码。问题是我想捕捉这些内部故障,尤其是当人们维护内部代码时。

标签: java unit-testing junit swallowed-exceptions


【解决方案1】:

如果您在 IDE 的调试器中执行测试,您可以将 IDE 配置为在引发异常时中断。

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

    • +1 - PMD 已经有一个规则来查找空的 catch 块。扩展它以制定规则以寻找其他常见的异常处理失败方式可能并不难。
    【解决方案3】:

    我相信 Exception 只是 SDK 库中的一个标准类。

    如果您将其提取、修改并将其放在 SDK 之前的类路径中的某个位置,我认为它应该替换 SDK 中的那个(如果不是,您可以将“新”异常放回 SDK jar 中)

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

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

    【讨论】:

    • 这并不容易,因为代码在 java.util.包,并且 JDK 有一些安全机制来防止你必须解决的那种修补。
    • @Yishai Strange,我知道有人这样做,但没有深入研究他们所做的事情的机制。我将不得不进一步研究它......(看过之后,这个页面似乎不同意:forums.sun.com/thread.jspa?threadID=30607&tstart=3420
    • 是的,引导类路径是基本思想,但这意味着一个单独制作和编译的类包装在一个单独的 jar 中,或者其他一些花哨的摆弄来分离这些实现,然后你就不能拥有该类与任何其他类(如 JUnit 类)交互,您的测试必须调用它,而不是相反。这是可行的,就是这么简单。
    【解决方案4】:

    我会尝试使用 AOP 来抛出故障。像这样的东西应该可以工作(注意,我没有测试过这个,你显然需要有 AspectJ Setup 才能使用 AOP 注释)

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

    } }

    【讨论】:

      【解决方案5】:

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

      【讨论】:

        【解决方案6】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-09-15
          • 2021-07-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多