我知道这样做的一种方法是:
@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 许可协议
你正在以错误的方式接近这个。只需测试您的功能:如果抛出异常,测试将自动失败。如果没有抛出异常,您的测试将全部变为绿色。
我注意到这个问题不时引起人们的兴趣,所以我会稍微扩展一下。
单元测试的背景
当您进行单元测试时,重要的是要为自己定义您认为的工作单元。基本上:提取您的代码库,可能包含也可能不包含代表单个功能的多个方法或类。
或者,如 Roy Osherove 所著的单元测试的艺术,第 2 版,第 11 页所定义:
重要的是要认识到,一个 工作单元 通常不仅仅是一种方法,但在最基本的层面上它是一种方法,之后它被其他工作单元封装。
理想情况下,每个单独的工作单元都应该有一个测试方法,这样您就可以随时查看哪里出错了。在此示例中,有一个名为
getUserById()
的基本方法,它将返回一个用户,总共有 3 个作品单元。第一个工作单元应该测试在有效和无效输入的情况下是否返回有效用户。
数据源抛出的任何异常都必须在这里处理:如果没有用户存在,应该有一个测试来证明当找不到用户时抛出异常。这方面的一个示例可能是
IllegalArgumentException
它被@Test(expected = IllegalArgumentException.class)
注释捕获。一旦您处理了这个基本工作单元的所有用例,您就提升了一个级别。在这里你做的完全一样,但你只处理来自当前级别正下方级别的异常。这可以使您的测试代码保持良好的结构,并允许您快速运行整个体系结构以找出哪里出了问题,而不必到处跳。
处理测试的有效和错误输入
此时应该清楚我们将如何处理这些异常。有两种类型的输入: 有效 输入和 错误 输入(严格意义上的输入是有效的,但不是正确的)。
当您使用 有效 输入时,您正在设置隐含的期望值,即您编写的任何测试都将起作用。
这样的方法调用可能如下所示:
existingUserById_ShouldReturn_UserObject
。如果此方法失败(例如:抛出异常),那么您就知道出了问题,您可以开始挖掘了。通过添加另一个使用 错误 输入并期待异常的测试 (
nonExistingUserById_ShouldThrow_IllegalArgumentException
),您可以查看您的方法是否执行了错误输入应该执行的操作。长话短说
您试图在测试中做两件事:检查有效输入和错误输入。通过将其拆分为两种方法,每种方法只做一件事,您将拥有更清晰的测试和更好地了解哪里出了问题。
通过牢记分层工作单元,您还可以减少层次结构中较高层所需的测试量,因为您不必考虑较低层中可能出错的每一件事:当前层之下的层是您的依赖项工作的虚拟保证,如果出现问题,它在您的当前层(假设较低层本身不会抛出任何错误)。