如何测试没有抛出异常?

新手上路,请多包涵

我知道这样做的一种方法是:

 @Test
public void foo() {
   try {
      // execute code that you expect not to throw Exceptions.
   } catch(Exception e) {
      fail("Should not have thrown any exception");
   }
}

有没有更清洁的方法来做到这一点? (可能使用 Junit 的 @Rule ?)

原文由 Ankit Dhingra 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.4k
2 个回答

你正在以错误的方式接近这个。只需测试您的功能:如果抛出异常,测试将自动失败。如果没有抛出异常,您的测试将全部变为绿色。

我注意到这个问题不时引起人们的兴趣,所以我会稍微扩展一下。

单元测试的背景

当您进行单元测试时,重要的是要为自己定义您认为的工作单元。基本上:提取您的代码库,可能包含也可能不包含代表单个功能的多个方法或类。

或者,如 Roy Osherove 所著的单元测试的艺术,第 2 版,第 11 页所定义:

单元测试 是一段自动化的代码,它调用被测试的工作单元,然后检查关于该单元的单个最终结果的一些假设。单元测试几乎总是使用单元测试框架编写的。它可以轻松编写并快速运行。它是值得信赖的、可读的和可维护的。只要生产代码没有改变,它的结果就是一致的。

重要的是要认识到,一个 工作单元 通常不仅仅是一种方法,但在最基本的层面上它是一种方法,之后它被其他工作单元封装。

在此处输入图像描述

理想情况下,每个单独的工作单元都应该有一个测试方法,这样您就可以随时查看哪里出错了。在此示例中,有一个名为 getUserById() 的基本方法,它将返回一个用户,总共有 3 个作品单元。

第一个工作单元应该测试在有效和无效输入的情况下是否返回有效用户。

数据源抛出的任何异常都必须在这里处理:如果没有用户存在,应该有一个测试来证明当找不到用户时抛出异常。这方面的一个示例可能是 IllegalArgumentException 它被 @Test(expected = IllegalArgumentException.class) 注释捕获。

一旦您处理了这个基本工作单元的所有用例,您就提升了一个级别。在这里你做的完全一样,但你只处理来自当前级别正下方级别的异常。这可以使您的测试代码保持良好的结构,并允许您快速运行整个体系结构以找出哪里出了问题,而不必到处跳。

处理测试的有效和错误输入

此时应该清楚我们将如何处理这些异常。有两种类型的输入: 有效 输入和 错误 输入(严格意义上的输入是有效的,但不是正确的)。

当您使用 有效 输入时,您正在设置隐含的期望值,即您编写的任何测试都将起作用。

这样的方法调用可能如下所示: existingUserById_ShouldReturn_UserObject 。如果此方法失败(例如:抛出异常),那么您就知道出了问题,您可以开始挖掘了。

通过添加另一个使用 错误 输入并期待异常的测试 ( nonExistingUserById_ShouldThrow_IllegalArgumentException ),您可以查看您的方法是否执行了错误输入应该执行的操作。

长话短说

您试图在测试中做两件事:检查有效输入和错误输入。通过将其拆分为两种方法,每种方法只做一件事,您将拥有更清晰的测试和更好地了解哪里出了问题。

通过牢记分层工作单元,您还可以减少层次结构中较高层所需的测试量,因为您不必考虑较低层中可能出错的每一件事:当前层之下的层是您的依赖项工作的虚拟保证,如果出现问题,它在您的当前层(假设较低层本身不会抛出任何错误)。

原文由 Jeroen Vannevel 发布,翻译遵循 CC BY-SA 3.0 许可协议

由于 SonarQube 的规则“squid:S2699”:“至少向该测试用例添加一个断言”,我偶然发现了这一点。

我有一个简单的测试,其唯一目标是在不抛出异常的情况下通过。

考虑这个简单的代码:

 public class Printer {

    public static void printLine(final String line) {
        System.out.println(line);
    }
}

可以添加什么样的断言来测试这个方法?当然,您可以围绕它进行 try-catch,但这只是代码膨胀。

解决方案来自 JUnit 本身。

如果没有抛出异常并且您想明确说明此行为,只需添加 expected 如下例所示:

 @Test(expected = Test.None.class /* no exception expected */)
public void test_printLine() {
    Printer.printLine("line");
}

Test.None.class 是预期值的默认值。

如果你 import org.junit.Test.None ,你可以这样写:

 @Test(expected = None.class)

您可能会发现它更具可读性。

原文由 Sven Döring 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题