0

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.

ksl
  • 4,519
  • 11
  • 65
  • 106
  • Consider using: https://stackoverflow.com/questions/6581188/is-there-an-executorservice-that-uses-the-current-thread – GhostCat Apr 06 '18 at 14:26
  • 1
    Remember to shut down ExecutorServices. You leak threads when you don't. – David Ehrmann Apr 06 '18 at 14:33
  • @DavidEhrmann I did have 'executor.shutdownNow()` at the end of each test while investigating this but it didn't make any difference to the failure. – ksl Apr 06 '18 at 14:41

0 Answers0