如果我为抛出一堆异常的函数编写测试用例,我应该在测试方法中为这些异常添加抛出声明,还是应该捕获每个单独的异常。正确的做法是什么?我相信try-catch是一种更好的方法,但在catch块中,我应该打印stacktrace吗?
例如,我有一个抛出AuthenticationException
的方法getGroups(String name)
。如果我写一个测试用例来检查当name
参数为null时是否抛出了IllegalArgumentException
,我该如何处理AuthenticationException
?我是应该将它添加到方法的throws部分,还是应该将异常包含在try-catch
块中。
@Test
public void testGetGroupsWithNull() throws AuthenticationException {
thrown.expect(IllegalArgumentException.class);
getGroups(null);
}
在上面的测试用例中,我只是添加了一个throws AuthenticationException
,但我想知道将异常封装在try-catch块中是否更好,以及在捕获异常后应该做什么。我可以打印堆栈跟踪。
我正在处理意外的异常AuthenticationException
,不是将它放在"throws"子句中,而是放在try/catch块中。
@Test
public void testGetGroupsWithNull() {
thrown.expect(IllegalArgumentException.class);
try {
getGroups(null);
} catch(AuthenticationExcption e) {
Assert.fail("Authentication Exception");
}
}
@Test(expected= IndexOutOfBoundsException.class)
public void empty() {
new ArrayList<Object>().get(0);
}
或:
@Test
public void testExceptionMessage() {
try {
new ArrayList<Object>().get(0);
fail("Expected an IndexOutOfBoundsException to be thrown");
} catch (IndexOutOfBoundsException anIndexOutOfBoundsException) {
assertThat(anIndexOutOfBoundsException.getMessage(), is("Index: 0, Size: 0"));
}
}
如果JUnit测试抛出意外异常,它将失败。这就是你想要的行为。因此,使用try/catch块是没有意义的。如果您期望出现异常,请使用ExpectedException规则(您显然从代码片段中了解该规则)。但无论你是否期待,都不要使用try/catch。
这意味着,如果您的异常是已检查异常,则需要一个throws子句。事实上,您经常需要在测试方法上使用throws子句,即使您不希望抛出异常,因为您的测试调用的方法有时会抛出已检查的异常。我已经养成了在每一种测试方法上都写throws Exception
的习惯。没有理由不这样做;这只是少了一件需要担心的事情。
注释更具交流性。
它表示测试期望在不强制读取器读取代码的情况下发生什么。
任何一个测试都应该只期望抛出一个异常,因为每个测试都应该测试一个行为。单个行为只能引发一个异常。
如果抛出任何其他异常,则表示测试失败。测试方法签名必须反映任何可能的检查异常,当然,调用相同方法的real代码也是如此。
使用写尽可能少的代码来解决问题的规则,您的第一个代码片段将获胜。因此,是的,将AuthenticationException
放入测试方法的throws
子句中。它更简洁易读。
由于我正在处理您的主题,所以我一直在寻找相同的问题,并且我找到了单元测试最佳实践的良好解释。从文章中摘录一些内容可以帮助你。
没有必要编写自己的catch块,因为JUnit框架会为您处理这种情况,所以这些块的存在只会导致测试失败。例如,假设您正在为以下方法编写单元测试:
final class Foo {
int foo(int i) throws IOException;
}
这里我们有一个方法,它接受一个整数并返回一个整数,如果遇到错误则抛出IOException。以下是编写单元测试的错误方法,该方法在通过七次测试时确认返回三次:
// Don't do this - it's not necessary to write the try/catch!
@Test
public void foo_seven()
{
try
{
assertEquals(3, new Foo().foo(7));
}
catch (final IOException e)
{
fail();
}
}
测试中的方法指定它可以抛出IOException,这是一个已检查的异常。因此,除非捕获异常或声明测试方法可以传播异常,否则单元测试不会编译。第二种选择是首选的,因为它可以缩短测试时间,提高测试重点:
// Do this instead
@Test
public void foo_seven() throws Exception
{
assertEquals(3, new Foo().foo(7));
}
我们声明测试方法抛出Exception,而不是抛出IOException。如果在调用被测方法的过程中发生任何异常,JUnit框架将确保该测试失败——不需要编写自己的异常处理。
您可以在本文中找到更多关于JUnit最佳实践的信息,如上文所述:http://www.kyleblaney.com/junit-best-practices/
希望能帮忙。