305

I'm trying to have one of my mocked objects throw a checked Exception when a particular method is called. I'm trying the following.

@Test(expectedExceptions = SomeException.class)
public void throwCheckedException() {
    List<String> list = mock(List.class);
    when(list.get(0)).thenThrow(new SomeException());
    String test = list.get(0);
}

public class SomeException extends Exception {
}

However, that produces the following error.

org.testng.TestException: 
Expected exception com.testing.MockitoCheckedExceptions$SomeException but got org.mockito.exceptions.base.MockitoException: 
Checked exception is invalid for this method!
Invalid: com.testing.MockitoCheckedExceptions$SomeException

Looking at the Mockito documentation, they only use RuntimeException, is it not possible to throw checked Exceptions from a mock object with Mockito?

Arthur Maltson
  • 5,760
  • 4
  • 30
  • 33

5 Answers5

365

Check the Java API for List.
The get(int index) method is declared to throw only the IndexOutOfBoundException which extends RuntimeException.
You are trying to tell Mockito to throw an exception SomeException() that is not valid to be thrown by that particular method call.

To clarify further.
The List interface does not provide for a checked Exception to be thrown from the get(int index) method and that is why Mockito is failing.
When you create the mocked List, Mockito will use the definition of List.class to creates its mock.

The behavior you are specifying with the when(list.get(0)).thenThrow(new SomeException()) doesn't match the method signature in List API, because get(int index) method does not throw SomeException() so Mockito fails.

If you really want to do this, then have Mockito throw a new RuntimeException() or even better throw a new ArrayIndexOutOfBoundsException() since the API specifies that that is the only valid Exception to be thrown.

Ahmed Nabil
  • 17,392
  • 11
  • 61
  • 88
John Engelman
  • 4,119
  • 1
  • 16
  • 12
  • While my real code wasn't actually using List, your answer applies for that method call as well. I was mocking the wrong method. Thank you. – Arthur Maltson Sep 21 '10 at 17:19
  • 2
    extra: Mocktio will not complain if you doThrow an a method without any throwables, but you will also get this exception – dwana Sep 25 '15 at 07:36
  • 12
    For Kotliners: Kotlin doesn't have checked exceptions, so you cannot normally declare (in the function signature) that the function throws an exception. However, you can annotate the function with `Throws` annotation to make the compiler generate the same bytecode as declaring throws in the equivalent Java code. See [here] (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-throws/index.html) for more details. – Javad Oct 04 '17 at 22:58
  • 3
    This check is enforced since the release of [Mockito 2.11.0 (see 2.10.3)](https://github.com/mockito/mockito/blob/release/2.x/doc/release-notes/official.md#2110-2017-10-14-published-to-jcentermaven-central). – JJD Mar 08 '18 at 11:48
  • Does the same logic apply for Scala as well? – Manu Chadha Aug 17 '20 at 06:07
  • @Javad could you add a snippet for the suggestion you added for Kotliners – Akash Verma Oct 19 '22 at 08:43
222

A workaround is to use a willAnswer() method.

For example the following works (and doesn't throw a MockitoException but actually throws a checked Exception as required here) using BDDMockito:

given(someObj.someMethod(stringArg1)).willAnswer( invocation -> { throw new Exception("abc msg"); });

The equivalent for plain Mockito would to use the doAnswer method

David Rawson
  • 20,912
  • 7
  • 88
  • 124
Deepak
  • 3,648
  • 1
  • 22
  • 17
  • 16
    or use `willAnswer( invocation -> { throw new Exception("abc msg"); }).given(someObj).someMethod(stringArg1);` when the method returns `void`. – Julien Kronegg May 17 '18 at 09:57
  • 25
    or use when(someObj.someMethod(stringArg1)).thenAnswer(invocation -> { throw new Exception("abc msg"); }); – Dmitri Algazin Mar 25 '19 at 12:44
  • Great workaround, thanks! For Kotliners who want to (1) use that seamlessly as an extension function and (2) be able to pass several args like `willThrow()` normally allows, I've written a [Gist](https://gist.github.com/dadouf/f9ec2b5d44f20295fcadb0e8834ad45a) – David Ferrand Feb 25 '20 at 10:36
33

There is the solution with Kotlin :

given(myObject.myCall()).willAnswer {
    throw IOException("Ooops")
}

Where given comes from

import org.mockito.BDDMockito.given

spottedmahn
  • 14,823
  • 13
  • 108
  • 178
Kevin ABRIOUX
  • 16,507
  • 12
  • 93
  • 99
26

Note that in general, Mockito does allow throwing checked exceptions so long as the exception is declared in the message signature. For instance, given

class BarException extends Exception {
  // this is a checked exception
}

interface Foo {
  Bar frob() throws BarException
}

it's legal to write:

Foo foo = mock(Foo.class);
when(foo.frob()).thenThrow(BarException.class)

However, if you throw a checked exception not declared in the method signature, e.g.

class QuxException extends Exception {
  // a different checked exception
}

Foo foo = mock(Foo.class);
when(foo.frob()).thenThrow(QuxException.class)

Mockito will fail at runtime with the somewhat misleading, generic message:

Checked exception is invalid for this method!
Invalid: QuxException

This may lead you to believe that checked exceptions in general are unsupported, but in fact Mockito is only trying to tell you that this checked exception isn't valid for this method.

David Moles
  • 48,006
  • 27
  • 136
  • 235
7

This works for me in Kotlin:

when(list.get(0)).thenThrow(new ArrayIndexOutOfBoundsException());

Note : Throw any defined exception other than Exception()

Alok Gupta
  • 1,806
  • 22
  • 21