ChatGPT解决这个技术问题 Extra ChatGPT

Mockito How to mock and assert a thrown exception?

I'm using mockito in a junit test. How do you make an exception happen and then assert that it has (generic pseudo-code)


N
NilsH

To answer your second question first. If you're using JUnit 4, you can annotate your test with

@Test(expected=MyException.class)

to assert that an exception has occured. And to "mock" an exception with mockito, use

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

this approach is unacceptable for case when you're testing method of an object that has some state. For example there is an object method that throws exception if you call it the second time. And you need to test to test that it does throw exception during the second method call, not the first one. If it throws MyException during the first method call (in the preparation stage) then it should fail the test. But with this approach we are not able to check during which method call the exception is thrown.
Though in this case we can catch exception from the first method call and wrap it in RuntimeException.
this does not work if the method doSomething() return type is void?
M
MariuszS

BDD Style Solution (Updated to Java 8)

Mockito alone is not the best solution for handling exceptions, use Mockito with Catch-Exception

Mockito + Catch-Exception + AssertJ

given(otherServiceMock.bar()).willThrow(new MyException());

when(() -> myService.foo());

then(caughtException()).isInstanceOf(MyException.class);

Sample code

Mockito + Catch-Exception + Assertj full sample

Dependencies

eu.codearte.catch-exception:catch-exception:2.0

org.assertj:assertj-core:3.12.2


What is "catch-exception"? Got a link?
what's caughtException ?
Got it, it's coming from com.googlecode.catchexception.CatchException.caughtException;
D
Daniel Treiber

If you want to test the exception message as well you can use JUnit's ExpectedException with 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() where does this come from?
I also prefer to use the @Rule, because this way I can test for expected message or cause or other stuff pertaining to the exception. For checking the cause of the exception, I use: expectedException.expectCause(Mockito.sameInstance(expectedException)) or expectedException.expectCause(Mockito.instanceOf(MyException.class)) and a few others that come in handy.
S
Selwyn

Updated answer for 06/19/2015 (if you're using java 8)

Just use assertj

Using assertj-core-3.0.0 + Java 8 Lambdas

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

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


worked for me...Also we can check the exception message as well.assertThatThrownBy(() -> myService.sumTingWong("badArg")).hasMessage("test") .isInstanceOf(IllegalArgumentException.class);
M
Manuel Spigolon

If you're using JUnit 4, and Mockito 1.10.x Annotate your test method with:

@Test(expected = AnyException.class)

and to throw your desired exception use:

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

D
Duncan Jones

Make the exception happen like this:

when(obj.someMethod()).thenThrow(new AnException());

Verify it has happened either by asserting that your test will throw such an exception:

@Test(expected = AnException.class)

Or by normal mock verification:

verify(obj).someMethod();

The latter option is required if your test is designed to prove intermediate code handles the exception (i.e. the exception won't be thrown from your test method).


Does the verify call assert the exception?
@NilsH No. But provided the when clause is correct, it must have thrown an exception.
if the method someMethod() return type is void, then it does not work like this. is there any way we can mock throw exception for void methods?
R
Rodrigo Martins de Oliveira

Use Mockito's doThrow and then catch the desired exception to assert it was thrown later.

@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);
}

A
Anupama Boorlagadda

Using mockito, you can make the exception happen.

when(testingClassObj.testSomeMethod).thenThrow(new CustomException());

Using Junit5, you can assert exception, asserts whether that exception is thrown when testing method is invoked.

@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());
}

Find a sample here: assert exception junit


Thanks ! Worked for me
C
Chetan Botre

I think this should do it for you.

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


J
JediCate

Or if your exception is thrown from the constructor of a class:

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

@Test
public void myTest() {    

    exception.expect(MyException.class);
    CustomClass myClass= mock(CustomClass.class);
    doThrow(new MyException("constructor failed")).when(myClass);  

}

e
eel ghEEz

Unrelated to mockito, one can catch the exception and assert its properties. To verify that the exception did happen, assert a false condition within the try block after the statement that throws the exception.


@MariuszS response correctly answers what you are saying is unrelated to Mockito
@pringi Thanks, I see that the question concerned both mocking an exception and catching it. I wonder though if this depends on any behaviour of the code under test.
S
Sam

Assert by exception message:

    try {
        MyAgent.getNameByNode("d");
    } catch (Exception e) {
        Assert.assertEquals("Failed to fetch data.", e.getMessage());
    }

If written like this, when there is no exception thrown, the test will still pass. Which is what we want to avoid in the first place