测试异常时的单元测试最佳实践

Unit test Best Practices when testing Exceptions

所以我一直在对 android 应用程序进行单元测试,虽然有些情况下我测试了失败场景,但我并没有完全按照这个答案所建议的方式测试它们().

我按照下面代码中显示的方式对其进行了测试。答案是建议您在测试方法签名上使用 "throws Exception",因为如果它实际上引发了您不期望的异常,它将无法通过测试。但是,无论有没有那段代码,我都尝试过,但都以同样的方式失败了。 上面提供的答案也通过使用 "rule" 来进行这种测试,我没有使用过,因为我需要的一切都在我的 try catch 块中,并且实例化是在 @Before 中完成的方法。

@Test
public void testMethod() {
   try{
   //code that will throw exception
   fail("Exception was not thrown");
   } catch (/* types of exceptions */) {
   //my asserts
   }
}

我所追求的是哪种方法被认为是 "best practice" 及其背后的原因。

@Test 注释的 expected 属性用于定义检查是否引发特定异常的测试用例。或者,还有用于更具体控制的 @Rules 注释和有点过时的 "try-catch" 习语。有关示例,请参阅 this and the junit wiki

@Test(expected = IllegalArgumentException.class)

我个人使用 assertThrows 并将结果分配给 Throwable,这样我就可以检查消息。 这样做的原因是,例如,当我需要检查 return IllegalArgument 的验证时,我可以检查消息是否是该字段的预期消息。

@Test
public void testSomething_shouldThrowException() {

  String expectedMessage = "Exception running the method";

  Throwable exception = Assertions.assertThrows(YourException.class, () 
    -> {
      bean.doSomething(dummyRequest);
    });

  Assert.assertEquals(expectedMessage, exception.getMessage());
}

因为这是用 JUnit4 标记的,所以我更喜欢使用 @Test 注释的预期属性

@Test(expected = NullPointerException.class)

但是,如果您需要检查抛出的异常的更多属性,您可以使用 ExpectedException,它非常强大:

@Rule
public ExpectedException exceptionRule = ExpectedException.none();

@Test
public void whenExceptionThrown_thenRuleIsApplied() {
    exceptionRule.expect(NumberFormatException.class);
    exceptionRule.expectMessage("For input string");
    Integer.parseInt("1a");
}

不过,我建议使用 JUnit 5,您可以在其中使用 Java 8 构造,例如传递 Lambda 进行检查,这使您的代码非常明确和简洁。

JUnit 4 和 JUnit 5 的好文章:https://www.baeldung.com/junit-assert-exception