Java:测试是否在更大的系统中捕获异常



我知道有很多关于这个话题的问题,但所有这些问题似乎都假设了两件事之一:

  1. 您只想测试是否抛出异常但未捕获,
  2. 您应该测试 try 块内的函数 径直

我不确定如何将这些选项应用于这种情况。 我有一个小的尝试/捕获块,如下所示:

try {
o.getDataContainer().build(...);
o2.setDataContainer(o.getDataContainer());
} catch (final Exception e) {
LOGGER.error("Data set failed", e);
}

如您所见,如果 o.getDataContainer() 返回 null,则会触发异常。 但是,随后会捕获该异常,并且测试工具将其视为成功的测试。 是否可以在不更改代码的情况下测试异常是否发生?

我问是因为我们的日志记录系统如果拾取捕获并记录的异常,则会触发故障单。由于忘记保护这样的东西是常见的人为错误,我想编写可以测试是否触发和捕获异常的 UT。 我无法删除 catch 块提供的全程序保护,但该错误也会导致用户体验下降,因为数据没有传递。 (我工作的地方几分钟的站点停机时间相当于数百万美元的损失。

换句话说:异常是一个错误,我们希望记录它并调查它,但如果这设法在生产中触发,我们不想冒整个网站崩溃的风险。

注意:这个try/catch位于一个更大的函数中,其中包含许多这样的try/catch块。 人们可以很容易地争论糟糕的整体设计,但修复它不是一种选择(至少没有大量的免费开发时间)。

更新:由于手头的任务不允许我花很多时间在这上面,所以我做了一个非常简单的通用测试,如果警卫和抓捕都被移除,我就可以继续前进,就会失败。 但是,我暂时不回答这个问题,希望继续对话。 我希望能够为每个新功能编写一个简单的UT,如果触发和捕获任何异常,这些功能就会失败。

忽略此代码的问题(有时你必须在猪身上涂口红,我猜),这就是我处理这种情况的方式。

我会使用 Mockito 和模拟o2,然后使用Answer来确保调用该方法。

测试可能如下所示:

@RunWith(MockitoJUnitRunner.class)
public class TestClass{
@Mock
O2 o2;
@Mock
O1 o1;
boolean exceptionThrown = false;
@Test
public void test(){
Mockito.doAnswer(new Answer<Void>(){     
public Void answer(InvocationOnMock invocation) throws Throwable {
exceptionThrown = true; 
throw new RuntimeException("some message");
}            
}).when(o2).setDataContainer(DataContainer.class);
}
}

从本质上讲,您可以在示例中模拟o2,并强制异常。

如果这不能完全满足您的要求,您可能需要模拟LOGGER并验证它是否使用LOGGER.error("some message");调用。不幸的是,模拟静态一点也不优雅,但它可以用PowerMock来完成。

您可以将自定义处理程序添加到 LOGGER,该处理程序仅在记录错误时引发。对于java.util.logging,你可以做这样的事情:

LOGGER.addHandler(new Handler() {
public void publish(LogRecord record) {
if ("Data set failed".equals(record.getMessage())) {
throw new RuntimeException(record.getThrown());
}
}
public void flush() {}
public void close() throws SecurityException {}
});

我认为log4j称它为"Appender",但同样的原则应该有效。请参阅如何在 log4j 中创建自己的追加器?或如何在 log4j2 中创建自定义追加器?

最新更新