180

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

MariuszS
  • 30,646
  • 12
  • 114
  • 155
stackoverflow
  • 18,348
  • 50
  • 129
  • 196

15 Answers15

246

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());
NilsH
  • 13,705
  • 4
  • 41
  • 59
  • 4
    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. – Sneg May 24 '17 at 18:07
  • Though in this case we can catch exception from the first method call and wrap it in RuntimeException. – Sneg May 24 '17 at 18:19
  • 1
    this does not work if the method doSomething() return type is void? – Abdul Mohsin Oct 08 '21 at 05:43
85

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

Dependencies

MariuszS
  • 30,646
  • 12
  • 114
  • 155
42

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

Selwyn
  • 3,118
  • 1
  • 26
  • 33
  • 1
    worked for me...Also we can check the exception message as well.assertThatThrownBy(() -> myService.sumTingWong("badArg")).hasMessage("test") .isInstanceOf(IllegalArgumentException.class); – Sritam Jagadev Nov 05 '19 at 07:34
  • This answer needs more upvotes. – Dave Jul 28 '22 at 01:30
37

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"));
}
Daniel Treiber
  • 1,411
  • 12
  • 9
  • `given()` where does this come from? – Mohammad Faisal Dec 18 '18 at 14:06
  • 2
    From mockito-core: https://static.javadoc.io/org.mockito/mockito-core/2.23.4/org/mockito/BDDMockito.html – Daniel Treiber Dec 18 '18 at 14:12
  • 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. – Crenguta S May 22 '19 at 08:20
21

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();
Manuel Spigolon
  • 11,003
  • 5
  • 50
  • 73
Prashant Kumar
  • 311
  • 2
  • 4
17

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);
}
Rodrigo Oliveira
  • 1,452
  • 4
  • 19
  • 36
16

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).

Duncan Jones
  • 67,400
  • 29
  • 193
  • 254
12

I think this should do it for you.

assertThrows(someException.class,
()-> mockedServiceReference.someMethod(param1,parme2,..));
Dale K
  • 25,246
  • 15
  • 42
  • 71
Chetan Botre
  • 151
  • 1
  • 7
9

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

Anupama Boorlagadda
  • 1,158
  • 1
  • 11
  • 19
6

An easy and short way that worked for me was:

assertThrows(YourException.class, () -> yourLogic())
belal
  • 61
  • 1
  • 2
3

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

}
JediCate
  • 396
  • 4
  • 8
0

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.

eel ghEEz
  • 1,186
  • 11
  • 24
  • @MariuszS response correctly answers what you are saying is unrelated to Mockito – pringi Nov 30 '17 at 11:16
  • @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. – eel ghEEz Dec 21 '17 at 04:42
0

Here is a way, how you can Mock and Assert the exception:

  1. Java 8 or above
  2. JUnit 5 -> org.junit.jupiter:5.X.X & org.mockito:4.X.X
// Mock an exception
when(mapperService.convertRequest(any())).thenThrow(new RuntimeException());

// Assert the exception
RuntimeException thrown = Assertions.assertThrows(RuntimeException.class, () -> {
            addOfferService.processData(deltaDetails);
        });
Assertions.assertEquals("Exception occurred during create data", thrown.getMessage());
0

Mockito fully supports stubbing methods to throw an exception, AssertJ is not necessary.

Code below. First the stuff that will be tested:

@Component
public class Blam
{
    public void blamIt()
    {
        System.out.println("blam");
    }
}

@Component
@RequiredArgsConstructor
public class Kapow
{
    private final Blam blam;

    public void aMethod()
    {
        blam.blamIt();
    }
}

Now the actual unit test (using Mockito and Junit 5):

@ExtendWith(MockitoExtension.class)
public class TestKapow
{
    private Kapow classToTest;

    @Mock
    private Blam mockBlam;

    @Mock
    private RuntimeException mockRuntimeException;

    @BeforeEach
    void beforeEach()
    {
        classToTest = new Kapow(mockBlam);
    }

    @Test
    void aMethod_blamItThrowsRuntimeException_exceptionEscapes()
    {
        final RuntimeException actualException;


        doThrow(mockRuntimeException).when(mockBlam).blamIt();


        actualException = assertThrows(RuntimeException.class, () -> classToTest.aMethod());

        assertNotNull(actualException);

        assertSame(mockRuntimeException, actualException);
    }
}

Some Notes:

  1. I find it to be a good practice to instantiate mock objects via the @Mock annotation.
  2. I prefer the doThrow(xxx).when(mockXxx).method form for throwing and exception during a unit test.
  3. You can "catch" the thrown exception when using the assertThrows method.
DwB
  • 37,124
  • 11
  • 56
  • 82
-3

Assert by exception message:

    try {
        MyAgent.getNameByNode("d");
    } catch (Exception e) {
        Assert.assertEquals("Failed to fetch data.", e.getMessage());
    }
Sam
  • 536
  • 1
  • 4
  • 9
  • 3
    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 – Christian Lim Jul 24 '20 at 07:49