6

如果我为一个抛出一堆异常的函数编写测试用例,我应该在我的测试方法中为这些异常添加一个 throws 声明,还是应该捕获每个单独的异常。正确的做法是什么?我相信 try-catch 是一种更好的方法,但是在 catch 块中我应该打印堆栈跟踪吗?

例如,我有一个getGroups(String name)throws的方法AuthenticationException。如果我编写一个测试用例来检查参数为空IllegalArgumentException时是否抛出了一个name,我该如何处理AuthenticationException?我是将它添加到我的方法的 throws 部分还是应该将异常包含在一个try-catch块中。

@Test
public void testGetGroupsWithNull() throws AuthenticationException {
 thrown.expect(IllegalArgumentException.class);
 getGroups(null);
}

在上面的测试用例中,我只是添加了一个throws AuthenticationException,但我想知道将异常包含在 try-catch 块中是否更好,以及在捕获异常后我应该做什么。我可以打印堆栈跟踪。

我正在处理意外异常AuthenticationException,方法是不将其放在“抛出”子句中,而是放在 try/catch 块中。

@Test
public void testGetGroupsWithNull() {
thrown.expect(IllegalArgumentException.class);
try {
  getGroups(null);
} catch(AuthenticationExcption e) {
  Assert.fail("Authentication Exception");
}
}
4

5 回答 5

5

JUnit 在这里有一篇很棒的文章:https ://github.com/junit-team/junit/wiki/Exception-testing关于这个主题。你可以做:

@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"));
      }
  }
于 2013-08-14T22:12:32.857 回答
4

如果 JUnit 测试抛出意外异常,它就会失败。这就是你想要的行为。因此,使用 try/catch 块没有任何意义。如果您期待异常,请使用 ExpectedException 规则(您显然知道,从您的代码片段)。但无论你是否期待,都不要使用 try/catch。

这意味着如果您的异常是已检查异常,则需要一个 throws 子句。事实上,您经常需要在您的测试方法上使用 throws 子句,即使您并不期望抛出异常,只是因为您的测试调用了一个有时会抛出已检查异常的方法。我已经养成了throws Exception在每一种测试方法上都写的习惯。没有理由不这样做;这只是少了一件需要担心的事情。

于 2013-08-14T22:30:19.537 回答
1

使用尽可能少的代码来解决问题的规则,你的第一个代码片段就赢了。所以是的,将其AuthenticationException放入您的测试方法的throws子句中。它更简洁易读。

于 2013-08-16T23:56:27.773 回答
1

注释更具交流性。

它表明测试预期会发生什么,而不会强迫读者阅读代码。

任何单个测试都应该只期望抛出一个异常,因为每个测试都应该测试一个行为。一个行为只能抛出一个异常。

如果抛出任何其他异常,则表示测试失败。当然,测试方法签名必须反映任何可能的检查异常,就像调用相同方法的真实代码一样。

于 2013-08-14T22:14:11.500 回答
0

自从我处理您的主题以来,我一直在寻找相同的问题,并且我找到了单元测试最佳实践的一个很好的解释。从文章中提取一点可以帮助你。

没有必要编写自己的 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));
}

我们声明测试方法抛出异常而不是抛出 IOException。如果在调用被测方法期间发生任何异常,JUnit 框架将确保该测试失败 - 无需编写您自己的异常处理。

您可以在本文中找到更多关于 JUnit 最佳实践的信息: http ://www.kyleblaney.com/junit-best-practices/

希望有所帮助。

于 2014-01-08T15:49:35.720 回答