Search code examples
javatddmockitospy

Mockito - configure a mock so it will call a method with an injected parameter


I have a method in a class, ConsoleHandler, an instance of which I'm spying on:

setIndexManager( IndexManager im );

I want to say "when you call this method, call it not with the parameter you want to call it with, but instead with such-and-such a parameter" (namely a mock object).

I tried doing this:

    doAnswer( new Answer<Void>(){
        @Override
        public Void answer(InvocationOnMock invocation) throws Throwable {
            ((ConsoleHandler)invocation.getMock()).setIndexManager( newMockIM );
            return null;
        }}).when( spyCH ).setIndexManager( any( IndexManager.class ));

... unfortunately this caused an infinite loop...

Then I thought: OK, if you can specify in the when clause that any IndexManager parameter should trigger this, except for mockIM, maybe you can stop that infinite recursion:

    doAnswer( new Answer<Void>(){
        @Override
        public Void answer(InvocationOnMock invocation) throws Throwable {
            ((ConsoleHandler)invocation.getMock()).setIndexManager( newMockIM );
            return null;
        }}).when( spyCH ).setIndexManager( not( newMockIM ));

... but not doesn't work like that...

Is there any way of doing this? I did quite a close examination of possible similar questions which came up but couldn't find anything.


Solution

  • Sure. Change your stubbing so that it only kicks in if the provided argument is not your mock.

    So the last line would be

    }}).when(spyCH).setIndexManager(AdditionalMatchers.not( ArgumentMatchers.eq(newMockIM)) );
    

    Then the call within your Answer won't re-trigger the stubbed call.

    Note

    I answered before you added the second half of your question, but I believe this is OK. The argument to not has to be a matcher, but you've provided a value. So all you were missing is the eq.