我正在使用 JUnit 为没有单元测试的遗留代码编写一些更高级别的测试。
大部分代码“吞下”了各种未经检查的异常,如 NullPointerExceptions(例如,仅打印堆栈跟踪并返回 null)。因此,即使在较低级别代码的各个点存在级联灾难,单元测试也可以通过。
有没有办法让第一个未经检查的异常测试失败,即使它们被吞下?
我能想到的唯一替代方法是编写一个自定义 JUnit 包装器来重定向 System.err,然后分析输出中的异常。
我正在使用 JUnit 为没有单元测试的遗留代码编写一些更高级别的测试。
大部分代码“吞下”了各种未经检查的异常,如 NullPointerExceptions(例如,仅打印堆栈跟踪并返回 null)。因此,即使在较低级别代码的各个点存在级联灾难,单元测试也可以通过。
有没有办法让第一个未经检查的异常测试失败,即使它们被吞下?
我能想到的唯一替代方法是编写一个自定义 JUnit 包装器来重定向 System.err,然后分析输出中的异常。
由于缺乏具体的解决方案,我的回答很笼统:
当您在修复遗留系统时遇到此类代码异味(例如,swalling 异常)时,最好逐步(逐个类)清理它们。代码质量工具(例如 Findbugs、PMD、Checkstyle 甚至 Sonar Quality Server)可以帮助您找到这些东西。
一种自动“捕获”被吞下的异常的方法是使用 AspectJ 编译器。当违反某些代码约定时,您可以声明方面以在 IDE 中生成编译时错误。或者,您可以在运行时编织被测类并让 AspectJ 重新抛出此类异常,以便 JUnit 运行程序记录它们。
如果您在 IDE 的调试器中执行测试,您可以将 IDE 配置为在引发异常时中断。
我相信 Exception 只是 SDK 库中的一个标准类。
如果您将其提取、修改并将其放在 SDK 之前的类路径中的某个位置,我认为它应该替换 SDK 中的那个(如果不是,您可以将“新”异常放回 SDK jar 中)
无论如何,您的新异常可以设置一个可以被测试框架读取的静态值。
可能不是最优雅的解决方案,但它不需要任何“魔法”
我会尝试使用 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;
}
} }
可以使用修改字节码的模拟框架或 AOP 框架来模拟您想要捕获的异常。我想你可以修改构造函数来抛出一个更致命的异常,或者在你的测试代码中设置一些标志。
也许您可以粘贴您要测试的代码。很可能您必须使用一些“重新映射器”测试框架,例如 powermock 或 jmockit 来操作 JVM 中的类加载器操作。但是被测类的样本将有助于确定所需的方法。