在 JUnit 中测试包含 try/catch 块的方法的最佳方法

Best way to test a method containing a try/catch block in JUnit

我有以下方法。该方法使用 Jackson ObjectMapper 转换 json 字符串的内容。如果 json 格式不正确,则会打印堆栈跟踪并将对象设置为空:

public ObjectTransferData extractJacksonObjectsFromFile(String json) {
  ObjectTransferData objectTransferData;
  try {
    objectTransferData = objectMapper.readValue(json, ObjectTransferData.class);
  } catch (Exception e) {
    e.printStackTrace();
    objectTransferData = null;
  }
  return objectTransferData;
}

我为可能格式错误的 json 字符串编写了 JUnit 单元测试,如下所示:

@Test
public void testExtractJacksonObjectsFromFile_malformedJson_expectNull(){
  String malformedJson = "{";
  ObjectTransferData result = myService.extractJacksonObjectsFromFile(malformedJson);
  assertNull(result);
}

本次测试通过。但它也将 e.printStackTrace() 打印到我的终端中,这在测试执行期间掩盖了实际的重要日志。测试执行的 reader 可能会造成混淆。

我想知道如何解决这个问题。我想到了这些想法:

  1. 删除 try/catch 并抛出异常。这将允许我像这样编写测试,而不是将堆栈跟踪记录到控制台中。
@Test
public void testExtractJacksonObjectsFromFile_malformedJson_expectException(){
  String malformedJson = "{";
  assertThrows(Exception.class, () ->
        objectImportService.extractJacksonObjectsFromFile(malformedJson)
  );
}

然而,缺点是实际应用程序现在会抛出此异常,并且不会通过 catch 块处理它来优雅地失败。

  1. 以某种方式抑制测试的异常记录。但这可能会导致在测试执行期间抑制实际错误的日志。

这个有点相关,但没有完全回答我的问题。 我可以将所有测试堆栈跟踪重定向到 this 之类的文件,但我不想在测试执行期间重定向实际异常。 告诉特定测试不打印堆栈跟踪将是理想的。

您需要决定是要更改应用程序行为(并按照您已经建议的那样报告异常)还是保持该行为,return 为 null。

但是还有第三种选择,特别是因为您正在进行单元测试: 将您的方法的功能分为两部分:

  1. 解析JSON并抛出异常的部分
  2. 一个捕获异常的包装函数,将其打印到标准输出并且 returns null

您的单元测试现在可以测试 1),而应用程序使用 2)。

如果你也不喜欢这样,你可以 - 在你的单元测试中 - 在调用异常抛出东西之前将 stdout 重定向到一些临时的 ByteArrayStream ,然后不仅检查 null 是否被 returned 而且如果字节数组接收到正确的数据。