I have a below scenario when setView is called then Presenter fetches some data over the network on a new thread. Test fails by giving this reason - Actually, there were zero interactions with this mock. But it should pass if interaction gets verified.

Testcase

@Test
public void checkUnoRate() {
    ratePresenter.setView(rateView,Constants.UNO);
    verify(rateView,times(1)).showRate(new Rate());
}

Inside "ratePresenter.setView"

Call<UnoRate> call1 = ratesAPI.getUnoRate();
            call1.enqueue(new Callback<UnoRate>() {
                @Override
                public void onResponse(Call<UnoRate> call,Response<UnoRate> response) {
                    UnoRate unoRate = response.body();
                    Rate rate = new Rate();
                    rate.setBuyRate(unoRate.getBuy());
                    rate.setSellRate(unoRate.getSell());
                    rate.setFee(0);
                    rateView.showRate(rate);
                    }

               });
1

There are 1 best solutions below

2
On BEST ANSWER

One very simple solution is to use Mockito's verification with timeout feature. This will retry the verification repeatedly up until the timeout, looking for the condition to pass at some point or another.

@Test
public void checkUnoRate() {
    ratePresenter.setView(rateView,Constants.UNO);
    verify(rateView, timeout(100).times(1)).showRate(new Rate());
}

The docs, however, warn against it: "This feature should be used rarely - figure out a better way of testing your multi-threaded system." This is probably because you're introducing a new aspect--time--as a proxy for the thing you really want to check, which is that all of the queues have been processed. You could even imagine a busy enough VM where a conservative timeout could cause the test to flake in automated testing systems but that works fine on development machines.

If feasible, you could switch your ratesAPI to use a synchronous executor, or instead you could add methods needed to your API accessor to block the test thread until all calls have returned asynchronously:

@Test
public void checkUnoRate() {
    ratePresenter.setView(rateView,Constants.UNO);
    ratesAPI.flush(); // Implement this to perform a Thread.join on the callback thread,
                      // or otherwise wait until all callbacks have been called.
    verify(rateView,times(1)).showRate(new Rate());
}

Or, to remove multithreading and external API interactions from your test, simulate the callback synchronously:

@Mock RatesAPI ratesApiMock;
@Mock Call<UnoRate> unoRateCallMock;
@Captor Callback<UnoRate> unoRateCallbackCaptor;

@Test
public void checkUnoRate() {
    // Set up mock.
    when(ratesApiMock.getUnoRate()).thenReturn(unoRateCallMock);

    // Perform the action.
    ratePresenter.setView(rateView,Constants.UNO);

    // Verify nothing happens yet.
    verify(rateView, never()).showRate(any());

    // Capture and trigger the callback.
    verify(unoRateCallMock).enqueue(unoRateCallbackCaptor.capture());
    unoRateCallbackCaptor.getValue().onResponse(yourCall, yourResponse);

    // Verify the asynchronous action.
    verify(rateView,times(1)).showRate(new Rate());
}

As a side note, eventually you'll probably want to verify against a different parameter than new Rate(). Mockito compares via equals methods when not using Mockito matchers.