Using verify on Spy object

I defined a spy bean:

@Bean
public IMyService myServiceSpy()
{
    return Mockito.spy(new MyServiceImpl());
}

In my test I want to capture the argument the service gets. Of course if I'll define the service as mock instead of spy, it'll work, but I want to activate service's real method and continue the flow, because I need the return value to be calculated by it.

@Inject
private IMyService myServiceSpy;

@Test
public void myTest()
{

//act   
//here invoking some service that will eventually invoke MyServiceImpl.

//assert
ArgumentCaptor<SomeObj> someObjCaptor = ArgumentCaptor.forClass(SomeObj.class);

try
{               
   Mockito.verify(myServiceSpy, Mockito.atLeastOnce()).create(someObjCaptor.capture());                 
}
catch(Exception e)
{
    Assert.fail();
}   

I'm failing on verify and getting the exception:

org.mockito.exceptions.base.MockitoException:  No argument value was captured! You might have forgotten to use argument.capture() in verify()... ...or you used capture() in stubbing but stubbed method was not called. Be aware that it is recommended to use capture() only with verify()

Examples of correct argument capturing:
    ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);
    verify(mock).doSomething(argument.capture());
    assertEquals("John", argument.getValue().getName());

1 answer

  • answered 2018-07-19 15:40 cavpollo

    I'm not entirely sure you should be using @Inject to spy over your service.

    This has worked fine for me in the past:

    import org.mockito.ArgumentCaptor;
    import org.mockito.Captor;
    import org.mockito.Spy;
    
    import static org.mockito.Mockito.verify;
    import static org.mockito.Mockito.atLeastOnce;
    
    ...
    
    @Spy
    private MyServiceImpl myServiceSpy;
    
    @Captor
    private ArgumentCaptor<SomeObj> someObjCaptor;
    
    @Test
    public void myTest()
    {
    
        ...
    
        try
        {               
           verify(myServiceSpy, atLeastOnce()).create(someObjCaptor.capture());
    
           SomeObj someObj = someObjCaptor.get();
    
           // Assert anything
        }
        catch(Exception e)
        {
            Assert.fail();
        }   
    
        ...
    
    }
    
    @Bean
    public MyServiceImpl myServiceImpl()
    {
        return new MyServiceImpl();
    }
    

    The annotations really simplify the code. Once you get used to them, it becomes much simpler to read the code, and to type it in =)