Don't understand "Wanted but not invoked" and "TooManyActualInvocations"

16,124 views
Skip to first unread message

Jean-Pierre Bergamin

unread,
Mar 5, 2012, 5:01:20 PM3/5/12
to moc...@googlegroups.com
Dear Mockito users

I'm totally stuck at the moment, because I do not understand the behavior of the following test cases. We have a spring based application and use mockito 1.9.0.
The mockito mocks are created in the spring xml file with

<bean id="mockedRepositoryRegistry" class="com.example.utils.MockFactory">
<property name="type" value="com.example.IRepositoryRegistry" />
</bean>

The MockFactory implements FactoryBean and simply returns Mockito.mock(type) in the getObject() method.
The mockedProcessRepository and mockedRepositoryRegistry in the following example are @Autowired into the processController (a Spring MVC controller).

The actual test class looks like:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/META-INF/spring/test-processcontroller-context.xml" })
public class ProcessControllerTests {

    @Autowired
    private IProcessRepository mockedProcessRepository;

    @Autowired
    private IRepositoryRegistry mockedRepositoryRegistry;

    @Autowired
    private ProcessController processController;

    private static final String PROCESS01_ID = "3e34d8c1-8a4b-4bcf-a1f7-99f5e3bad09c";
    private static final String PROCESS01_NAME = "Process 1";
    private static final String PROCESS02_ID = "5beb41dc-69a8-4a27-9e21-26d490cd94b7";
    private static final String PROCESS02_NAME = "Process 2";

    private static final IProcess process01 = new ProcessMock(PROCESS01_ID, PROCESS01_NAME);
    private static final IProcess process02 = new ProcessMock(PROCESS02_ID, PROCESS02_NAME);

    @Before
    public void setUp() {
        reset(mockedRepositoryRegistry);
        reset(mockedProcessRepository);
        List<IProcess> processes = new ArrayList<IProcess>();
        processes.add(process01);
        processes.add(process02);

        when(mockedProcessRepository.findAll()).thenReturn(Closable.from(processes));
        when(mockedProcessRepository.findByUuid(PROCESS01_ID)).thenReturn(process01);
        when(mockedProcessRepository.findByUuid(PROCESS02_ID)).thenReturn(process02);
        when(mockedRepositoryRegistry.getLifecycleRepositoryFor(IProcess.class))
                .thenReturn(mockedProcessRepository);
    }

    // Tests methods....
}

So far so good. The following test case passes:
    @Test
    public void testDeleteNofFound() {
        processController.delete("not a valid uuid");
        verify(mockedProcessRepository, never()).delete(any(IProcess.class));
    }
The controller never invokes the delete method of the repository, because an invalid/unknown uuid is passed in. I totally agree with that...

Now to the part I do not understand anymore. I expect the following test case to succeed:
    @Test
    public void deleteShouldSucceed() {
        processController.delete(PROCESS01_ID);
        verify(mockedProcessRepository).delete(process01);
    }
The delete method of the processController invokes the delete method of the mockedProcessRepository with process01 as argument.
But it fails with the stacktrace:

Wanted but not invoked:
iProcessRepository.delete(
    Process [name=Process 1, uuid=3e34d8c1-8a4b-4bcf-a1f7-99f5e3bad09c, internalId=0]
);
-> at com.example.test.ui.web.process.ProcessControllerTests.deleteFails(ProcessControllerTests.java:82)

However, there were other interactions with this mock:
-> at com.example .ui.web.internal.AbstractEntityController.delete(AbstractEntityController.java:80)
-> at com.example .ui.web.internal.AbstractEntityController.delete(AbstractEntityController.java:82)

I can't understand why the invocation is not recognized. When I step through the code, I can see that the repository in the controller is the mockedProcessRepository and that the argument that is passed into the delete method is "process01".
The following test method fails with the same error message:
    @Test
    public void deleteFailsToo() {
        processController.delete(PROCESS01_ID);
        IProcess p = mockedProcessRepository.findByUuid(PROCESS01_ID);
        verify(mockedProcessRepository).delete(p);
    }

Playing around, I found out that this method succeeds!!! But where's the difference to the ones above? I don't get it...

    @Test
    public void deleteSucceeds() {
        processController.delete(PROCESS01_ID);
        verify(mockedProcessRepository).delete(mockedProcessRepository.findByUuid(PROCESS01_ID));
    }

It gets even stranger. In this test case, mockito reports TooManyActualInvocations of a method I do not verify at all:

    @Test
    public void strangeTooManyInvocationsError() {
        processController.delete(PROCESS01_ID);
        IProcess p = mockedProcessRepository.findByUuid(PROCESS01_ID);
        verify(mockedProcessRepository).delete(mockedProcessRepository.findByUuid(PROCESS01_ID));
    }

It fails with:

org.mockito.exceptions.verification.TooManyActualInvocations: 
iProcessRepository.findByUuid(
    "3e34d8c1-8a4b-4bcf-a1f7-99f5e3bad09c"
);
Wanted 1 time:
-> at com.example.test.ui.web.process.ProcessControllerTests.strangeTooManyInvocationsError(ProcessControllerTests.java:102)
But was 2 times. Undesired invocation:
-> at  com.example.test.ui.web.process.ProcessControllerTests.strangeTooManyInvocationsError(ProcessControllerTests.java:101)

Why does mockito think I wanted to check for invocations of "findByUuid"? I do only verify for invocations of the "delete" method. 

So my questions are:
  • Why does the  deleteShouldSucceed fail?
  • Why does  strangeTooManyInvocationsError  verify the invocations of findByUuid?
  • What could be the reason for this behavior?
I'm clueless...

Best regards,
James

Szczepan Faber

unread,
Mar 6, 2012, 6:30:07 AM3/6/12
to moc...@googlegroups.com
Hey James,

You've stepped on one of the syntax limitations I'm afraid:

verify(mockedProcessRepository).delete(mockedProcessRepository.findByUuid(PROCESS01_ID));

or simpler:

verify(mock).foo(mock.bar());

is not supported. Mockito does not know which method should verify foo() or bar(). It cannot be fixed due to language and syntax choices. More over we cannot even give any warning (unless someone has some brillant idea? :) However, if only you have used different mocks, such syntax would have worked:

verify(mock).foo(mockTwo.bar()); //works

It's because when different mocks are used in that use case, Mockito has chance to distinguish between the verified call and the 'auxiliary' call.

The only choice you have is to separate the 'auxiliary' call:

Bar bar = mock.bar();
verify(mock).foo(bar);

Hope that helps!

--
You received this message because you are subscribed to the Google Groups "mockito" group.
To view this discussion on the web visit https://groups.google.com/d/msg/mockito/-/cQgKUO6BBfkJ.
To post to this group, send email to moc...@googlegroups.com.
To unsubscribe from this group, send email to mockito+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/mockito?hl=en.



--
Szczepan Faber
Principal engineer@gradleware
Lead@mockito

Jean-Pierre Bergamin

unread,
Mar 8, 2012, 5:14:23 AM3/8/12
to moc...@googlegroups.com
Hi

Am Dienstag, 6. März 2012 12:30:07 UTC+1 schrieb szczepiq:
You've stepped on one of the syntax limitations I'm afraid:

verify(mockedProcessRepository).delete(mockedProcessRepository.findByUuid(PROCESS01_ID));

or simpler:

verify(mock).foo(mock.bar());

is not supported. Mockito does not know which method should verify foo() or bar(). It cannot be fixed due to language and syntax choices. More over we cannot even give any warning (unless someone has some brillant idea? :) However, if only you have used different mocks, such syntax would have worked:

verify(mock).foo(mockTwo.bar()); //works

It's because when different mocks are used in that use case, Mockito has chance to distinguish between the verified call and the 'auxiliary' call.

Thanks for the explanation. This explains the TooManyActualInvocations error.

The only choice you have is to separate the 'auxiliary' call:

Bar bar = mock.bar();
verify(mock).foo(bar);

This is what I tried in the test method deleteFailsToo in my original post. In this case mockito means that foo has not been called with bar as argument, whereas I'm absolutely sure it has been called this way.
Any ideas why I get the "Wanted but not invoked" error in this case?

Best regards,
James
 
Hope that helps!

To unsubscribe from this group, send email to mockito+unsubscribe@googlegroups.com.

For more options, visit this group at http://groups.google.com/group/mockito?hl=en.

Szczepan Faber

unread,
Mar 8, 2012, 6:17:34 AM3/8/12
to moc...@googlegroups.com
On Thu, Mar 8, 2012 at 11:14 AM, Jean-Pierre Bergamin <jpber...@gmail.com> wrote:
Hi

Am Dienstag, 6. März 2012 12:30:07 UTC+1 schrieb szczepiq:
You've stepped on one of the syntax limitations I'm afraid:

verify(mockedProcessRepository).delete(mockedProcessRepository.findByUuid(PROCESS01_ID));

or simpler:

verify(mock).foo(mock.bar());

is not supported. Mockito does not know which method should verify foo() or bar(). It cannot be fixed due to language and syntax choices. More over we cannot even give any warning (unless someone has some brillant idea? :) However, if only you have used different mocks, such syntax would have worked:

verify(mock).foo(mockTwo.bar()); //works

It's because when different mocks are used in that use case, Mockito has chance to distinguish between the verified call and the 'auxiliary' call.

Thanks for the explanation. This explains the TooManyActualInvocations error.

The only choice you have is to separate the 'auxiliary' call:

Bar bar = mock.bar();
verify(mock).foo(bar);

This is what I tried in the test method deleteFailsToo in my original post. In this case mockito means that foo has not been called with bar as argument, whereas I'm absolutely sure it has been called this way.
Any ideas why I get the "Wanted but not invoked" error in this case?

Maybe it wasn't called after all, maybe it was called but not on 'that' mock. Maybe some other overloaded method was actually called. Maybe the method is final... Warm up your debugger and find out :)
 
To view this discussion on the web visit https://groups.google.com/d/msg/mockito/-/XTkazmkO-sgJ.

To post to this group, send email to moc...@googlegroups.com.
To unsubscribe from this group, send email to mockito+u...@googlegroups.com.

For more options, visit this group at http://groups.google.com/group/mockito?hl=en.

Marcin Zajączkowski

unread,
Mar 9, 2012, 4:38:00 PM3/9/12
to moc...@googlegroups.com
On 2012-03-05 23:01, Jean-Pierre Bergamin wrote:
> Dear Mockito users
>
> I'm totally stuck at the moment, because I do not understand the behavior
> of the following test cases. We have a spring based application and use
> mockito 1.9.0.
> The mockito mocks are created in the spring xml file with
>
> <bean id="mockedRepositoryRegistry" class="com.example.utils.MockFactory">
> <property name="type" value="com.example.IRepositoryRegistry" />
> </bean>
>
> The MockFactory implements FactoryBean and simply
> returns Mockito.mock(type) in the getObject() method.

Not directly connected to your question, but to simplify mock creation
in a Spring context (and get some new interesting features like
overriding real beans already defined in a Spring context) your can
also take a look at Springockito:
https://bitbucket.org/kubek2k/springockito/wiki/Home

Regards
Marcin

> - Why does the deleteShouldSucceed fail?
> - Why does strangeTooManyInvocationsError verify the invocations of
> findByUuid?
> - What could be the reason for this behavior?


>
> I'm clueless...
>
> Best regards,
> James
>


--
http://blog.solidsoft.info/ - Working code is not enough

Russell Bateman

unread,
Mar 9, 2012, 4:59:06 PM3/9/12
to moc...@googlegroups.com
"Springocktito"?

Gasp!

Spring: "We will add your technological distinctiveness to own. Your
technology will adapt to serve us. Resistance is futile."

Hehehe...

:-)

Reply all
Reply to author
Forward
0 new messages