6

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

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

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

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

4

6 回答 6

4

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

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

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

于 2010-05-06T17:28:49.830 回答
4

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

于 2010-05-06T17:17:28.100 回答
1

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

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

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

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

于 2010-05-06T17:44:42.200 回答
1

我会尝试使用 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;

  }

} }

于 2010-05-07T04:30:29.990 回答
0

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

于 2010-05-06T17:30:21.800 回答
0

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

于 2010-05-07T07:11:33.080 回答