我知道有很多关于这个话题的问题,但所有这些问题似乎都假设了两件事之一:
- 您只想测试是否抛出异常但未捕获,
- 您应该测试 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 中创建自定义追加器?