Mockito如何模拟和断言抛出异常?

183

我正在一个Junit测试中使用Mockito。如何让异常发生并断言它已经发生了(通用伪代码)?

15个回答

250

首先回答你的第二个问题。如果你正在使用JUnit 4,你可以使用注解来为你的测试进行标注:

@Test(expected=MyException.class)

要断言异常已发生。使用Mockito“模拟”异常,请使用

when(myMock.doSomething()).thenThrow(new MyException());

4
当测试具有一些状态的对象方法时,这种方法是不可接受的。例如,存在一个对象方法,如果第二次调用它会抛出异常。您需要测试以确保它在第二次方法调用期间确实抛出异常,而不是在第一次调用期间抛出异常。如果它在第一次方法调用(准备阶段)期间抛出MyException,则应该使测试失败。但是使用这种方法,我们无法检查在哪个方法调用期间引发异常。 - Sneg
虽然在这种情况下,我们可以从第一个方法调用中捕获异常并将其包装在RuntimeException中。 - Sneg
1
如果方法 doSomething() 的返回类型是 void,那么这行代码就不起作用了吗? - Abdul Mohsin

85

3
"catch-exception"是什么?有链接吗? - Duncan Jones
什么是caughtException - Arar
明白了,它来自于 com.googlecode.catchexception.CatchException.caughtException; - Arar
catch-exception 仍会打印堆栈跟踪吗? - Ahmed Hasn.

43

如果您使用的是Java 8,针对2015年6月19日更新答案(Updated answer),只需使用assertj。

使用assertj-core-3.0.0 + Java 8 Lambda表达式

@Test
public void shouldThrowIllegalArgumentExceptionWhenPassingBadArg() {
assertThatThrownBy(() -> myService.sumTingWong("badArg"))
                                  .isInstanceOf(IllegalArgumentException.class);
}

参考:http://blog.codeleak.pl/2015/04/junit-testing-exceptions-with-java-8.html


1
对我有用...我们也可以检查异常消息。assertThatThrownBy(() -> myService.sumTingWong("badArg")).hasMessage("test") .isInstanceOf(IllegalArgumentException.class); - Sritam Jagadev
1
这个回答需要更多的赞。 - Dave

37

如果你想测试异常消息,你可以使用JUnit的ExpectedException与Mockito:

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

@Test
public void testExceptionMessage() throws Exception {
    expectedException.expect(AnyException.class);
    expectedException.expectMessage("The expected message");

    given(foo.bar()).willThrow(new AnyException("The expected message"));
}

given() 这个函数是从哪里来的? - Mohammad Faisal
2
来自mockito-core: https://static.javadoc.io/org.mockito/mockito-core/2.23.4/org/mockito/BDDMockito.html - Daniel Treiber
我也倾向于使用@Rule,因为这样我可以测试异常的期望消息、原因或其他相关内容。为了检查异常的原因,我使用:expectedException.expectCause(Mockito.sameInstance(expectedException)) 或 expectedException.expectCause(Mockito.instanceOf(MyException.class)) 和其他一些方便的方法。 - Crenguta S

21

如果您正在使用JUnit 4和Mockito 1.10.x,请在测试方法上加上注释:

@Test(expected = AnyException.class)

要抛出所需的异常,请使用:

Mockito.doThrow(new AnyException()).when(obj).callAnyMethod();

18

使用Mockito的doThrow,然后捕获所需的异常以断言稍后是否抛出。

@Test
public void fooShouldThrowMyException() {
    // given
    val myClass = new MyClass();
    val arg = mock(MyArgument.class);
    doThrow(MyException.class).when(arg).argMethod(any());
    Exception exception = null;

    // when
    try {
        myClass.foo(arg);
    } catch (MyException t) {
        exception = t;
    }

    // then
    assertNotNull(exception);
}

16
让异常以这种方式发生:
when(obj.someMethod()).thenThrow(new AnException());

通过断言测试将抛出这样一个异常来验证这是否发生:

@Test(expected = AnException.class)

或者通过普通的模拟验证:

verify(obj).someMethod();

如果你的测试旨在证明中间代码处理异常(即该异常不会从你的测试方法中抛出),则需要选择后一种选项。


verify 调用会断言异常吗? - NilsH
@NilsH 不是。但是只要 when 子句正确,它一定会抛出异常。 - Duncan Jones
1
如果方法 someMethod() 的返回类型是 void,则它不会像这样工作。我们有没有办法模拟抛出 void 方法的异常? - Abdul Mohsin

13

我认为这应该对你有所帮助。

assertThrows(someException.class,
()-> mockedServiceReference.someMethod(param1,parme2,..));

10
使用mockito,您可以制造异常。 when(testingClassObj.testSomeMethod).thenThrow(new CustomException()); 使用Junit5,您可以断言异常,确保在调用测试方法时抛出了该异常。
@Test
@DisplayName("Test assert exception")
void testCustomException(TestInfo testInfo) {
    final ExpectCustomException expectEx = new ExpectCustomException();

     InvalidParameterCountException exception = assertThrows(InvalidParameterCountException.class, () -> {
            expectEx.constructErrorMessage("sample ","error");
        });
    assertEquals("Invalid parametercount: expected=3, passed=2", exception.getMessage());
}

在此处找到一个示例:断言异常JUnit


谢谢!对我有用。 - HariKishore K

6
一个对我有效的简单方法是:
assertThrows(YourException.class, () -> yourLogic())

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接