Mockito在例外Junit 4.10之后验证

时间:2012-11-05 00:00:02

标签: java junit mockito junit-rule

我正在测试一个带有预期异常的方法。我还需要验证在抛出异常之后调用了一些清理代码(在模拟对象上),但看起来忽略了验证。这是代码。我使用Junit ExpectedException Rule来验证预期的异常。

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

@Test
public void testExpectedException()
{
   MockedObject mockObj = mock(MockedObj.class);
   MySubject subject = new MySubject(mockedObj);
   expectedEx.expect(MyException.class);
   expectedEx.expectMessage("My exception message.");
   subject.someMethodThrowingException();
   verify(mockObj).
       someCleanup(eq(...));
}

verify似乎完全被忽略了。无论我在verify中使用什么方法,我的测试都是通过,这不是我想要的。

知道为什么会这样吗?

4 个答案:

答案 0 :(得分:66)

ExpectedException通过wrapping your entire test methodJUnit @Rule的try-catch块中工作。当你的代码抛出异常时,它会将堆栈上升到最近的try / catch,这恰好在ExpectedException实例中(它会检查它是你期望的异常)。

在Java中,如果方法中发生未捕获的异常,控件将永远不会返回到该方法中的语句。这里适用相同的规则:控制永远不会返回到异常后测试中的语句。

从技术上讲,您可以将验证放在finally块中,但往往是a bad habit编辑:您的被测系统可能会抛出一个意外的异常,或者根本没有异常,这会给您一个有用的失败消息和跟踪;但是,如果该失败导致您的验证或断言在finally块中失败,那么Java将显示该消息而不是关于意外异常或意外成功的消息。这可能使调试变得困难,特别是因为您的错误将来自错误根本原因的代码行,错误地暗示其上方的代码成功。

如果您确实需要在异常后验证状态,则在每个方法的基础上,您始终可以恢复到此习语:

@Test
public void testExpectedException()
{
  MockedObject mockObj = mock(MockedObj.class);
  MySubject subject = new MySubject(mockedObj);
  try {
    subject.someMethodThrowingException();
    fail("Expected MyException.");
  } catch (MyException expected) {
    assertEquals("My exception message.", expected.getMessage());
  }
  verify(mockObj).someCleanup(eq(...));
}

更新:使用Java 8的lambda表达式,您可以在try块concisely enough to be useful中包装函数接口调用。我想这种语法的支持将进入许多标准测试库。

assertThrows(MyException.class,
    () -> systemUnderTest.throwingMethod());

答案 1 :(得分:5)

catch-exception

更优雅的解决方案
@Test
public void testExpectedException()
{
    MockedObject mockObj = mock(MockedObject.class);
    MySubject subject = new MySubject(mockObj);

    when(subject).someMethodThrowingException();

    then(caughtException())
            .isInstanceOf(MyException.class)
            .hasMessage("My exception message.");

    verify(mockObj).someCleanup(eq(...));
}

答案 2 :(得分:4)

我还没有尝试过,但除了Jeff Bowman的优秀答案外,您可以选择使用带有try ... finally结构的ExpectedException规则,将您的验证语句放在finally块中。

答案 3 :(得分:1)

一旦UT中引发了异常,下面的所有代码将被忽略。

@Test(expected = Exception.class)
public void testExpectedException() {
   MockedObject mockObj = mock(MockedObj.class);
   MySubject subject = new MySubject(mockedObj);
   subject.doSomething(); // If this line results in an exception then all the code below this will be ignored.
   subject.someMethodThrowingException();
   verify(mockObj).
       someCleanup(eq(...));
}

要解决此问题并验证所有拨打的电话,我们可以将 try 最终一起使用。

@Test(expected = Exception.class)
    public void testExpectedException() {
          MockedObject mockObj = mock(MockedObj.class);
          MySubject subject = new MySubject(mockedObj);
          try {
               subject.someMethodThrowingException(); 
          } finally {
             verify(mockObj).
             someCleanup(eq(...));
          }
}