The following class calls a function MyService::execute
on another thread.
public class Foo
{
@Inject
private MyService m_service;
@Inject
private ExecutorService m_executor;
public void foo()
{
MyRequest myRequest = new MyRequest("bar");
System.out.println("TP1");
m_executor.execute( () ->
{
System.out.println("TP2");
m_service.execute(myRequest);
System.out.println("TP3");
} );
System.out.println("TP4");
}
}
I have created some unit tests that check execute
is called with the correct arguments. MyService
is mocked.
public class FooTests
{
private final MyService m_myService = Mockito.mock(MyService.class);
@Test
public final void foo1()
{
final ExecutorService executor = Executors.newSingleThreadExecutor();
InjectionBinder injectionBinder = new InjectionBinder(m_myService, executor);
// some code that calls foo()
ArgumentCaptor<MyRequest> argument = ArgumentCaptor.forClass(MyRequest.class);
Mockito.verify(m_myService, Mockito.times(1)).execute(argument.capture());
// check arguments
}
@Test
public final void foo2()
{
final ExecutorService executor = Executors.newSingleThreadExecutor();
InjectionBinder injectionBinder = new InjectionBinder(m_myService, executor);
// some code that calls foo()
ArgumentCaptor<MyRequest> argument = ArgumentCaptor.forClass(MyRequest.class);
Mockito.verify(m_myService, Mockito.times(1)).execute(argument.capture());
// check arguments
}
}
The tests run OK on Windows and OSX but foo2
regularly rails on Linux.
The reason for the failure is that the mock is not called:
org.mockito.exceptions.verification.WantedButNotInvoked:
Wanted but not invoked:
myService.execute(<Capturing argument>);
-> at FooTests.foo2(#line number)
Actually, there were zero interactions with this mock.
However I do see the print statements to stdout around the call to m_service.execute
in Foo
.
I am using JUnit 4.12 and Mockito 2.2.26.
What am I missing?
EDIT
I've figured it out. Sometimes the test runs to completion before MyService::execute
is scheduled on the other thread.
Adding a short wait in my test after calling foo
and before verifying the call to MyService::execute
fixes the problem.