关于java:jUnit测试用例是否应该在throws声明或try catch块中处理默认异常

Should jUnit test cases handle default exceptions in a throws declaration or in a try catch block

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

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

1
2
3
4
5
@Test
public void testGetGroupsWithNull() throws AuthenticationException {
 thrown.expect(IllegalArgumentException.class);
 getGroups(null);
}

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

我通过不将它放在'throws'子句中而是放在try / catch块中来处理意外异常AuthenticationException

1
2
3
4
5
6
7
8
9
@Test
public void testGetGroupsWithNull() {
thrown.expect(IllegalArgumentException.class);
try {
  getGroups(null);
} catch(AuthenticationExcption e) {
  Assert.fail("Authentication Exception");
}
}


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

1
2
3
4
@Test(expected= IndexOutOfBoundsException.class)
public void empty() {
  new ArrayList<Object>().get(0);
}

要么:

1
2
3
4
5
6
7
8
9
@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块的EVER没有意义。如果您期望发生异常,请使用ExpectedException规则(您显然知道该规则,来自您的代码段)。但无论你是否期待,不要使用try / catch。

这意味着如果您的异常是已检查的异常,则需要throws子句。实际上,您通常需要在测试方法上使用throws子句,即使您不希望抛出异常,只是因为您的测试调用的方法可能会导致SUSETIMES抛出已检查的异常。我养成了在每一种测试方法上编写throws Exception的习惯。没有理由不这样做;而且只需要担心一件事。


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


注释更具沟通性。

它表示测试期望发生的事情,而不会强迫读者阅读代码。

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

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


我只是在寻找同样的问题,因为我正在处理你的主题,我找到了单元测试最佳实践的一个很好的解释。从文章中略微提取可以帮助您。

编写自己的catch块只是为了使测试失败,因为JUnit框架会为您处理这种情况。例如,假设您正在为以下方法编写单元测试:

1
2
3
final class Foo {
  int foo(int i) throws IOException;
}

这里我们有一个方法接受一个整数并返回一个整数,并在遇到错误时抛出IOException。这是编写单元测试的错误方法,它确认方法在传递七时返回三:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 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,这是一个经过检查的异常。因此,除非您捕获异常或声明测试方法可以传播异常,否则单元测试将无法编译。第二种选择是首选,因为它会导致更短,更集中的测试:

1
2
3
4
5
6
// 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/

希望能有所帮助。