Mockito Invocation Listener determine Source

I have a simple Interface and mock it with an InvocationListener (simulated by verbose logging option).

    final SampleInterface sampleIf = mock(SampleInterface.class, withSettings().verboseLogging());

    System.out.println("-> Modify return value");
    when(sampleIf.getIt()).thenReturn("Result");
    System.out.println("-> Call getter");
    assertEquals("Result", sampleIf.getIt());
    System.out.println("-> Verify getter call");
    verify(sampleIf).getIt();

as a result i get the following output:

-> Modify return value

###### Logging method invocation #1 on mock/spy ######## sampleInterface.getIt(); invoked: -> at

de.sambalmueslie.samanunga.test.TesterTest.test(TesterTest.java:31)
has returned: "null"

-> Call getter

###### Logging method invocation #2 on mock/spy ######## stubbed: -> at

de.sambalmueslie.samanunga.test.TesterTest.test(TesterTest.java:31) sampleInterface.getIt(); invoked: -> at de.sambalmueslie.samanunga.test.TesterTest.test(TesterTest.java:33)
has returned: "Result" (java.lang.String)

-> Verify getter call

###### Logging method invocation #3 on mock/spy ######## sampleInterface.getIt(); invoked: -> at

de.sambalmueslie.samanunga.test.TesterTest.test(TesterTest.java:35)
has returned: "null"

my question is, how could i isolate the real getter call from the calls done by the mockito framework?

I like the have the following output:

-> Modify return value -> Call getter

###### Logging method invocation #2 on mock/spy ######## stubbed: -> at

de.sambalmueslie.samanunga.test.TesterTest.test(TesterTest.java:31) sampleInterface.getIt(); invoked: -> at de.sambalmueslie.samanunga.test.TesterTest.test(TesterTest.java:33)
has returned: "Result" (java.lang.String)

-> Verify getter call

edit - example without mock

    System.out.println("-> Calling anything not mocked");
    sampleIf.callMe();
    System.out.println("-> Verify call");
    verify(sampleIf).callMe();

-> Calling anything not mocked

###### Logging method invocation #4 on mock/spy ######## sampleInterface.callMe(); invoked: -> at

de.sambalmueslie.samanunga.test.TesterTest.test(TesterTest.java:38)
has returned: "null"

-> Verify call

###### Logging method invocation #5 on mock/spy ######## sampleInterface.callMe(); invoked: -> at

de.sambalmueslie.samanunga.test.TesterTest.test(TesterTest.java:40)
has returned: "null"

1 answer

  • answered 2017-11-12 21:21 Alexandre Dupriez

    From your problem statement, I believe you would like to be notified of the invocation on the stub from the code under test, and exclude the invocations generated from the test code when formulating the expectations on the mocked object.

    You can indeed achieve this with an InvocationListener. I wrote below a listener which filters the notifications passed to the verbose invocation logger used in your example.

    final InvocationListener listener = new InvocationListener() {
      final VerboseMockInvocationLogger logger = new VerboseMockInvocationLogger();         
    
      @Override
      public void reportInvocation(MethodInvocationReport methodInvocationReport) {
        if (methodInvocationReport.getLocationOfStubbing() != null) {
          logger.reportInvocation(methodInvocationReport);                  
        }
      }
    };
    
    MockSettings settings = Mockito.withSettings().invocationListeners(listener); 
    SampleInterface sampleIf = Mockito.mock(SampleInterface.class, settings);
    ...
    

    Which yields the output:

    -> Modify return value
    -> Call getter
    ############ Logging method invocation #1 on mock/spy ########
       stubbed: -> at a.a.A.a(A.java:29)
    sampleInterface.getIt();
       invoked: -> at a.a.A.a(A.java:31)
       has returned: "Result" (java.lang.String)
    
    -> Verify getter call
    

    I used Mockito 1.10.19 to test this.

    Edit

    Ok, I understand - you also want to be notified of unstubbed method calls. In this case indeed I think using an InvocationListener alone is not enough. As such, I am not aware of an easy way to discriminate "real" method calls (stubbed or unstubbed) from the definition of expectations through the framework provided by Mockito.

    If you know in advance which methods are stubbed and which are not, you could use a default Answer for your unstubbed method calls. A default answer can be provided when you create the mock (Mockito.mock(type, defaultAnswer). It will be called for unstubbed method calls only. This, in addition to the InvocationListener, could be used to collect method invocations on your mocks.

    However, even if we could segregate the method calls which we knew are stubbed from those which aren't, I doubt we would like to separate the logic in two different constructs like this and I wouldn't advise for it, as it seems not consistent and error-prone to me.