Josh Laird
Josh Laird

Reputation: 7224

How to mock and verify a callback in method using Mockito

Within this method, I want to mock and ensure that mSharedPrefsManager gets called when I don't pass in a certain email string.

@Override
public void retrieveWithEmail(final String email, final WelcomeContract.Presenter presenter)
{
    retrieveInteractor.buildRetrieveRequest(email, new RetrieveImpl.OnRetrieveCompletedListener()
    {
        @Override
        public void onRetrieveCompleted(final MaitreBaseGson retrieveResponse, RetrieveImpl retrieveClass)
        {
            if (retrieveResponse.getStatus().equals(mContext.getString(R.string.ok)))
            {
                if (!email.equals("[email protected]"))
                    mSharedPrefsManager.storePoints(Integer.parseInt(retrieveResponse.getData().getPoints()));
                presenter.updateSilhouette(retrieveResponse);
            }
            // Silently swallow failures
        }
    });
}

However, with my test I'm not able to catch whether mSharedPrefsManager is called. Mockito says that .storePoints() is never called. I thought about doing a doReturn().when() but as this is within the method that wouldn't work, would it?

How do I catch the interactions on sharedPrefsManager?

Mockito also says that .updateSilhouette() is not called. Do I need to mock onRetrieveCompleted() somehow?

@RunWith(MockitoJUnitRunner.class)
public class WelcomeInteractorTest
{
    @Mock
    RetrieveImpl retrieveInteractor;

    @Mock
    WelcomePresenter welcomePresenter;

    @Mock
    SharedPrefsManager sharedPrefsManager;

    @Mock
    Context context;

    @InjectMocks WelcomeInteractorImpl welcomeInteractor;

    @Mock
    RetrieveImpl.OnRetrieveCompletedListener onRetrieveCompletedListener;

    @Test
    public void RetrieveWithCertainEmail_SavePoints()
    {
        welcomeInteractor.retrieveWithEmail("[email protected]", welcomePresenter);
        verify(retrieveInteractor).buildRetrieveRequest(eq("[email protected]"), any(RetrieveImpl.OnRetrieveCompletedListener.class));
        verify(sharedPrefsManager).storePoints(any(Integer.class));
        verify(welcomePresenter).updateSilhouette(any(MaitreBaseGson.class));
    }
}

Upvotes: 3

Views: 4571

Answers (2)

Josh Laird
Josh Laird

Reputation: 7224

Attempting to use @Spy caused a lot of issues for me as RetrieveImpl interacts with a network.

I instead used a Captor and captured the callback.

@Captor
private ArgumentCaptor<RetrieveImpl.OnRetrieveCompletedListener> mOnRetrieveCompletedListenerCaptor;

...

@Test
public void isTest()
{
    ...
    verify(retrieveInteractor).buildRetrieveRequest(eq(email), mOnRetrieveCompletedListenerCaptor.capture());
    mOnRetrieveCompletedListenerCaptor.getValue().onRetrieveCompleted(mockMaitreBaseGsonSuccessful, retrieveInteractor);
}

Upvotes: 1

Maciej Kowalski
Maciej Kowalski

Reputation: 26522

You are mocking:

@Mock
RetrieveImpl retrieveInteractor;

This means that when you call retrieveInteractor.buildRetrieveRequest(..), the real implementation is not invoked and eventually the methods that you expect to be called within that method call are never called..

Try using @Spy instead, this will actually allow for the real implementation to be called and you can verify that object also:

@Spy
RetrieveImpl retrieveInteractor;

Just one the side.. in think you are testing too much there and going to deep in your verifications.

That test in my opinion should be done for the RetrieveImpl.OnRetrieveCompletedListener class. Not the one that is in your question.

But thats just to my taste..

Upvotes: 0

Related Questions