46

I'm using Mockito. I want to throw a RuntimeException when an unstubbed method is called.

Is there any way to do this?

SQB
  • 3,926
  • 2
  • 28
  • 49
Hlib
  • 2,944
  • 6
  • 29
  • 33

4 Answers4

44

You can set a default answer for a mock. All methods that aren't stubbed will use this default answer.

public void testUnstubbedException() {
    // Create a mock with all methods throwing a RuntimeException by default
    SomeClass someClass = mock( SomeClass .class, new RuntimeExceptionAnswer() );

    doReturn(1).when(someClass).getId(); // Must use doReturn

    int id = someClass.getId(); // Will return 1

    someClass.unstubbedMethod(); // Will throw RuntimeException
}

public static class RuntimeExceptionAnswer implements Answer<Object> {

    public Object answer( InvocationOnMock invocation ) throws Throwable {
        throw new RuntimeException ( invocation.getMethod().getName() + " is not stubbed" );
    }

}

Note that you cannot use when with this functionality, since the method is called before when (How does mockito when() invocation work?) and it will throw a RuntimeException before the mock goes into stubbing mode.

Therefore, you must use doReturn for this to work.

Community
  • 1
  • 1
Tom Verelst
  • 15,324
  • 2
  • 30
  • 40
  • it's too bad this requires `doReturn` and a little extra work than one would expect for such a common desire – Charlie Mar 10 '20 at 23:01
15

The best way to do this is with the verifyNoMoreInteractions and ignoreStubs static methods. Call these after the "act" part of your test; and you'll get a failure if any unstubbed methods were called but not verified.

verifyNoMoreInteractions(ignoreStubs(myMock));

This is described at https://static.javadoc.io/org.mockito/mockito-core/2.8.47/org/mockito/Mockito.html#ignore_stubs_verification although I believe that the code example there currently contains a misprint.

Isaac Kwan
  • 99
  • 2
  • 10
Dawood ibn Kareem
  • 77,785
  • 15
  • 98
  • 110
  • 13
    This doesn't help if your test has crashed obscurely before this point due to a null dereference caused by a call to an unmocked method. – David Given Dec 04 '15 at 16:05
0

Refinement over Tom's answer https://stackoverflow.com/a/15835255/1484823

Mockito now provides builtin support with a default answer which throws exception, and can be specified either with @Mock annotation

    @Mock(answer = Answers.RETURNS_SMART_NULLS)
    private BackingAppDeploymentService backingAppDeploymentService;

or

    private BackingAppDeploymentService  backingAppDeploymentService =
      Mockito.mock(BackingAppDeploymentService.class, new ReturnsSmartNulls());

See https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#RETURNS_SMART_NULLS

If your code uses the object returned by an unstubbed call you get a NullPointerException. This implementation of Answer returns SmartNull instead of null. SmartNull gives nicer exception message than NPE because it points out the line where unstubbed method was called. You just click on the stack trace.

ReturnsSmartNulls first tries to return ordinary values (zeros, empty collections, empty string, etc.) then it tries to return SmartNull. If the return type is final then plain null is returned.

ReturnsSmartNulls will be probably the default return values strategy in Mockito 4.0.0

Community
  • 1
  • 1
Guillaume Berche
  • 3,049
  • 2
  • 17
  • 18
  • 2
    This is not what was asked. You are not getting a runtime exception if the "smart null" returned is never used. So, this does not answer the question that was about "getting an exception when forgetting to mock a method" – the_dark_destructor Dec 23 '21 at 15:50
-1

You mock an entire class and the result is that all methods will return null.

Then you can use doReturn(...) to change that behavior. Similarly, you can use doThrow(...) to make (as I recall only void) methods throw exceptions.

Does that answer your question?

Anders R. Bystrup
  • 15,729
  • 10
  • 59
  • 55