Hot questions for Using Mockito in callback

Question:

Let's say we have the following function to test

fun loadData(dataId: Long, completion: (JsonElement?, Exception?) -> Unit) {
    underlayingApi.post(url = "some/rest/url",
            completion = { rawResult, exception ->
                val processedResult = processJson(rawResult)
                completion(processedResult, exception)
            })
}

It's clear to me how to mock, inject, stub and verify the calls to underlayingApi.

How to verify the result returned via completion(processedResult, exception)?


Answer:

To test the lambdas behavior, the underlayingApi has to be mocked where the lambda is invoked via the InvoactionOnMock object like this.

    `when`(underlayingApi.post(eq("some/rest/url"),
                               any())).thenAnswer {
        val argument = it.arguments[1]
        val completion = argument as ((rawResult: String?, exception: Exception?) -> Unit)
        completion.invoke("result", null)
    }

This leads to the invocation of the callback within the object under test. Now to check if the callback out of the object under test is working verify it like that.

    objUnderTest.loadData(id,
                          { json, exception ->
                              assert....
                          })

Question:

Here i got a sample of code in presenter. How do i make write a test for onSuccess and onFailure in retrofit call

public void getNotifications(final List<HashMap<String,Object>> notifications){

        if (!"".equalsIgnoreCase(userDB.getValueFromSqlite("email",1))) {
            UserNotifications userNotifications =
                    new UserNotifications(userDB.getValueFromSqlite("email",1),Integer.parseInt(userDB.getValueFromSqlite("userId",1).trim()));
            Call call = apiInterface.getNotifications(userNotifications);
            call.enqueue(new Callback() {
                @Override
                public void onResponse(Call call, Response response) {
                    UserNotifications userNotifications1 = (UserNotifications) response.body();


                    if(userNotifications1.getNotifications().isEmpty()){
                        view.setListToAdapter(notifications);
                        onFailure(call,new Throwable());
                    }
                    else {
                        for (UserNotifications.Datum datum:userNotifications1.getNotifications()) {
                            HashMap<String,Object> singleNotification= new HashMap<>();
                            singleNotification.put("notification",datum.getNotification());
                            singleNotification.put("date",datum.getDate());
                            notifications.add(singleNotification);
                        }
                        view.setListToAdapter(notifications);
                    }
                }

                @Override
                public void onFailure(Call call, Throwable t) {
                    call.cancel();
                }
            });
        }
    }

}

How do i write unittesting to cover all cases for this piece of code.

Thanks


Answer:

When you want to test different responses from service (API) it's probably best to mock it and return what you need.

    @Test
    public void testApiResponse() {
      ApiInterface mockedApiInterface = Mockito.mock(ApiInterface.class);
      Call<UserNotifications> mockedCall = Mockito.mock(Call.class);

      Mockito.when(mockedApiInterface.getNotifications()).thenReturn(mockedCall);

      Mockito.doAnswer(new Answer() {
        @Override
        public Void answer(InvocationOnMock invocation) throws Throwable {
          Callback<UserNotifications> callback = invocation.getArgumentAt(0, Callback.class);

          callback.onResponse(mockedCall, Response.success(new UserNotifications()));
          // or callback.onResponse(mockedCall, Response.error(404. ...);
          // or callback.onFailure(mockedCall, new IOException());

          return null;
        }
      }).when(mockedCall).enqueue(any(Callback.class));

      // inject mocked ApiInterface to your presenter
      // and then mock view and verify calls (and eventually use ArgumentCaptor to access call parameters)
    }

Question:

I have an Android app that I'm working on and trying to write unit tests for it. The app is written with the MVP architecture and I am trying to test the Presenter-class.

Simplified method I'm trying to test looks like this:

public void userPressedButton() {
    service.loadData(new Callback<Data>{
        @Override
        onResponse(Data data) {
            view.showData(data);
        }
    });
}

Now I want to verify that when the userPressedButton method is called view.showData(data) is called.

I have tried several approaches but I can't seem to figure out how to test this.

Any ideas?

Edit: to clarify, I want to write a unit test


Answer:

Interesting case.

What i would do is to:

1) - Create a concrete class for that particular Callback:

public class MyCallback implements Callback<Data>{

    private View view;

    public MyCallback(View view){
        this.view = view;
    } 

    @Override
    onResponse(Data data) {
        view.showData(data);
    }
}

Now for this class you can write a unit test which would check whether the onResponse method calls the showData method of the view field.

2) Having extacted the implementation to a concrete class, from the perspective of the class which contains the userPressedButton method, it really is not essential what happens inside of the Callback class. It is important that a concrete implementation of that interface has been passed:

public void userPressedButton() {
    service.loadData(new MyCallback(view));
}

and finally the test:

@InjectMocks
MyClass myClass;

@Mock
Service service;

@Captor
ArgumentCaptor argCaptor;

@Before
public void init(){
     MockitoAnnotations.initMocks(this);
}

@Test
public void shouldUseMyCallback(){
     // Arrange

     // set up myClass for test

     // Act
     myClass.userPressedButton();

    Mockito.verify(service).loadData(argCaptor.capture());

    // Assert
    assertTrue(argCaptor.getValue instance of MyCallback);
}

So we check whether the loadData method has been called with proper implementation.

Thats how i would test your case.

Question:

when I was sync I wrote unit tests mocking the persistence part and check the caller's behavior. Here is an example about what I usually did:

@Mock
private OfferPersistenceServiceImpl persistenceService;
@Inject
@InjectMocks
private OfferServiceImpl offerService;
...
@Test
public void createInvalidOffer() {
  offer = new Offer(null, null, null, null, null, 4, 200D, 90D);
  String expectedMessage = Offer.class.getName() + " is not valid: " + offer.toString();
  Mockito.when(persistenceService.create(offer)).thenThrow(new IllegalArgumentException(expectedMessage));
  Response response = offerService.create(offer);
  Mockito.verify(persistenceService, Mockito.times(1)).create(offer);
  Assert.assertEquals(INVALID_INPUT, response.getStatus());
  String actualMessage = response.getEntity().toString();
  Assert.assertEquals(expectedMessage, actualMessage);
}

But now I fell in love with Vertx.io (to which I am pretty new) and I want to be async. Nice. But Vertx has handlers, so the new persistence component to mock looks like this:

...
mongoClient.insert(COLLECTION, offer, h-> {
  ...
});

So I am guessing how to mock handler h to tests class who's using that mongoClient or even if it is the right way to test with Vertx.io. I am using vertx.io 3.5.0, junit 4.12 and mockito 2.13.0. Thanks.

Update I tried to follow tsegimond suggestion but I can't get how Mockito's Answer and ArgumentCaptor can help me. Here is what I tried so far. Using ArgumentCaptor:

JsonObject offer = Mockito.mock(JsonObject.class);
Mockito.when(msg.body()).thenReturn(offer);         
Mockito.doNothing().when(offerMongo).validate(offer);
RuntimeException rex = new RuntimeException("some message");
...
ArgumentCaptor<Handler<AsyncResult<String>>> handlerCaptor =
ArgumentCaptor.forClass(Handler.class);
ArgumentCaptor<AsyncResult<String>> asyncResultCaptor =
ArgumentCaptor.forClass(AsyncResult.class);
offerMongo.create(msg);
Mockito.verify(mongoClient,
Mockito.times(1)).insert(Mockito.anyString(), Mockito.any(), handlerCaptor.capture());
Mockito.verify(handlerCaptor.getValue(),
Mockito.times(1)).handle(asyncResultCaptor.capture());
Mockito.when(asyncResultCaptor.getValue().succeeded()).thenReturn(false);
Mockito.when(asyncResultCaptor.getValue().cause()).thenReturn(rex);
Assert.assertEquals(Json.encode(rex), msg.body().encode());

and using Answer:

ArgumentCaptor<AsyncResult<String>> handlerCaptor =
ArgumentCaptor.forClass(AsyncResult.class);
AsyncResult<String> result = Mockito.mock(AsyncResult.class);
Mockito.when(result.succeeded()).thenReturn(true);
Mockito.when(result.cause()).thenReturn(rex);
Mockito.doAnswer(new Answer<MongoClient>() {
  @Override
  public MongoClient answer(InvocationOnMock invocation) throws Throwable {
    ((Handler<AsyncResult<String>>)
    invocation.getArguments()[2]).handle(handlerCaptor.capture());
        return null;
      }
    }).when(mongoClient).insert(Mockito.anyString(), Mockito.any(),
Mockito.any());
userMongo.create(msg);
Assert.assertEquals(Json.encode(rex), msg.body().encode());

And now I got confused. Is there a way to mock an AsyncResult to let it return false on succeed()?


Answer:

Finally I got some times to investigate and I made it. Here is my solution.

@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(VertxUnitRunner.class)
@PrepareForTest({ MongoClient.class })
public class PersistenceTest {

private MongoClient mongo;
private Vertx vertx;

@Before
public void initSingleTest(TestContext ctx) throws Exception {
  vertx = Vertx.vertx();
  mongo = Mockito.mock(MongoClient.class);
  PowerMockito.mockStatic(MongoClient.class);
  PowerMockito.when(MongoClient.createShared(Mockito.any(), Mockito.any())).thenReturn(mongo);
  vertx.deployVerticle(Persistence.class, new DeploymentOptions(), ctx.asyncAssertSuccess());
}

@SuppressWarnings("unchecked")
@Test
public void loadSomeDocs(TestContext ctx) {
  Doc expected = new Doc();
  expected.setName("report");
  expected.setPreview("loremipsum");
  Message<JsonObject> msg = Mockito.mock(Message.class);
  Mockito.when(msg.body()).thenReturn(JsonObject.mapFrom(expected));
  JsonObject result = new JsonObject().put("name", "report").put("preview", "loremipsum");
  AsyncResult<JsonObject> asyncResult = Mockito.mock(AsyncResult.class);
  Mockito.when(asyncResult.succeeded()).thenReturn(true);
  Mockito.when(asyncResult.result()).thenReturn(result);
  Mockito.doAnswer(new Answer<AsyncResult<JsonObject>>() {
    @Override
    public AsyncResult<JsonObject> answer(InvocationOnMock arg0) throws Throwable {
    ((Handler<AsyncResult<JsonObject>>) arg0.getArgument(3)).handle(asyncResult);
    return null;
    }
  }).when(mongo).findOne(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any());
  Async async = ctx.async();
  vertx.eventBus().send("persistence", new JsonObject(), msgh -> {
    if (msgh.failed()) {
    System.out.println(msgh.cause().getMessage());
    }
    ctx.assertTrue(msgh.succeeded());
    ctx.assertEquals(expected, Json.decodeValue(msgh.result().body().toString(), Doc.class));
    async.complete();
  });
  async.await();
  }
}

Use Powemockito to mock the MongoClient.createShared static method, so you'll have your mock when verticle starts. Mocking async handler is a bit of code to write. As you can see mocking start at Message<JsonObject> msg = Mockito.mock(Message.class); and ends at Mockito.doAnswer(new Answer.... In the Answer's method pick the handler param and force it to handle your async result then you're done.

Question:

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("certain@email.com"))
                    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("certain@email.com", welcomePresenter);
        verify(retrieveInteractor).buildRetrieveRequest(eq("certain@email.com"), any(RetrieveImpl.OnRetrieveCompletedListener.class));
        verify(sharedPrefsManager).storePoints(any(Integer.class));
        verify(welcomePresenter).updateSilhouette(any(MaitreBaseGson.class));
    }
}

Answer:

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..

Question:

I'm trying to test one class which makes a method call and wait from response throug a listener.

These are the interfaces inside the interactor. When I call fetch, then one of the listener fuctions is called back.

interface Interactor {
    void fetch(int offset, int size);
}

interface InteractorListener {
    void onReady(List<Result> results);

    void onError();
}

public class MyInteractor implements Interactor{

    private ImageInteractorListener listener;

    public MyInteractor() {}

    public onAttach(ImageInteractorListener listener) {
        this.listener = listener;
    }

    public void fetch(int offset, int size) {
        // Make asyncrhonous task
        // and manage the response in the next method
    }

    public void onAsyncroouTaskResponse() {
        if (someChecks) {
            listener.onReady(List<Result> results);
        } else {
            listener.onError();
        }
    }
}

public class MyClass implements ImageInteractorListener {

    public MyClass() {
        MyInteractor interactor = new Interactor();
        interactor.onAttach(this);
        interactor.fetch(1,1);
    }

    @Override
    void onReady(List<Result> results) {
        // doThings
    }

    @override
    void onError() {
        // doThings
    }
}

This is how my classes are maked. I need to test MyClass, so I need to mock Interactor callback

I have tried different sollutions with different problems, so right now I don't have a final code or error. But no one works..

Thank you.


Answer:

Assuming that you're testing MyClass you can just manually call your callback

// Test that errors are handled

// Given
Interactor interactor = mock(Interactor.class);
MyClass myClass = new MyClass(interactor);

// When
interactor.fetch(0, 0); // this call is optional, I just added it for clarity
myClass.onError();

// Then
// verify something

Question:

When using Mockito you can stub a method call like:

when(mock.someMethod("some arg"))
    .thenThrow(new RuntimeException())
    .thenReturn("foo");

But when your method returns void you need to stub with this format:

    doAnswer(new Answer() {..).when(mock). someMethod("some arg");

Imagine I have a Worker.class like this

class Worker {

   void doWork(Callback callback) {
        boolean success= ...;
        if(success){
            callback.onSuccess();
        }else {
            callback.onFail();
        }
   }

}

You can stub the calls with this code:

    doAnswer(new Answer() {
        @Override
        public Object answer(InvocationOnMock invocation) throws Throwable {
            Callback callback= invocation.getArguments()[0];
            callback.onSuccess();
            return null;
        }
    }).when(mockWorker).doWork(any(Callback.class));

Now imagine I want to stub that three consecutive calls to the worker to call onFail, onSuccess, onFail how can I do that? Do I need to reconfigure the mock inside each answer(InvocationOnMock invocation) call?


Answer:

Okey found the answer. You just need to chain the calls to doAnswer like:

doAnswer(new Answer() {
    @Override
    public Object answer(InvocationOnMock invocation) throws Throwable {
        Callback callback= invocation.getArguments()[0];
        callback.onFail();
        return null;
    }
}).
doAnswer(new Answer() {
    @Override
    public Object answer(InvocationOnMock invocation) throws Throwable {
        Callback callback= invocation.getArguments()[0];
        callback.onSuccess();
        return null;
    }
}).
doAnswer(new Answer() {
    @Override
    public Object answer(InvocationOnMock invocation) throws Throwable {
        Callback callback= invocation.getArguments()[0];
        callback.onFail();
        return null;
    }
}).when(mockWorker).doWork(any(Callback.class));

Question:

In mockito, I want to mock a method that returns some value and also has to invoke a callback

For example, here is the service method:

String fetchString(Callback<String> callback);

I want the return value to happen before the callback is invoked. I looked into using Mockito.doAnswer(..) but can't seem to figure out how to make the method invoke the callback after the return statement. Example:

when(mockService.fetchString(any(Callback.class)).thenAnswer(
    new Answer<String>() {
        String answer(InvocationOnMock invocation) {
            ((Callback<String>) invocation.getArguments()[0]).onResult("callback string");
            return "return string";
        }
    });

As you can see in the example above: the callback is invoked before the value is returned. This does't test asynchronous callbacks properly. Is there a way to make the callback method be called after the value is returned?

I know that argumentCaptor can be used here, but is there an alternative that doesn't involve manually calling the callback?

Something that is a combination of doAnswer(..) and thenReturn(..)?


Answer:

The best way to achieve this is to use ArgumentCaptor, as mentioned by @talex.

The way I used it is:

Service method:

String fetchString(Callback<String> callback);

JUnit Test:

ArgumentCaptor<Callback> captor = ArgumentCaptor.forClass(Callback.class);
when(mockService.fetchString(captor.capture()).thenReturn("return string");

String answer = mockService.fetchString(callbackToTest);
// callback is invoked after the service method returned the value
captor.getValue().onResult("callback string");

assertEquals("return string", answer);
verify(callbackToTest).onResult(eq("callback string"));

Question:

I have been trying to mock the callback with no success. Here is an example code:

public class TestService {
    private UtilService utilService;

    private LoadingCache<String, String> cache= CacheBuilder.newBuilder()
            .build(new CacheLoader<String, String>() {
                public String load(String key) throws Exception {
                    System.out.println("key = " + key);
                    return getKey(key);
                }
            });

    public String getkeyFromCache(String key) throws ExecutionException {
        return cache.get(key);
    }

    @VisibleForTesting
    public String getKey(String key) {
        return utilService.getKey(key);
    }
}

And a test case like this:

@RunWith(MockitoJUnitRunner.class)
public class TestServiceTest {

    public static final String MYKEY = "Mykey";
    @Spy
    TestService testService=new TestService();

    @Before
    public void before() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testCache() throws ExecutionException {
        doReturn(MYKEY).when(testService).getKey(MYKEY);
        String result=testService.getkeyFromCache(MYKEY);
        String result2nd=testService.getkeyFromCache(MYKEY);
        verify(testService,times(1)).getKey(MYKEY);
    }

}

But it looks like it is not invoked

Wanted but not invoked:
testService.getKey("Mykey");
-> at utils.TestServiceTest.testCache(TestServiceTest.java:38)

However, there were other interactions with this mock:
-> at utils.TestServiceTest.testCache(TestServiceTest.java:36)
-> at utils.TestServiceTest.testCache(TestServiceTest.java:37)

    at utils.TestServiceTest.testCache(TestServiceTest.java:38)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
    at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

I want to test the cache functionality but not the UtilService one, so I want to mock it. I can't think of a way to use Answer or Captor for this test or I would have.


Answer:

Your issue is that you've created the spy yourself. So the callback will be tied to the real method. Allowing Mockito to deal with the object creation solves the issue. (I'm using mockito 1.10.19)

I've refactored your test code:

@RunWith(MockitoJUnitRunner.class)
public class TestServiceTest {

    public static final String MYKEY = "Mykey";
    @Spy
    TestService testService;

    @Test
    public void testCache() throws ExecutionException {
        doReturn(MYKEY).when(testService).getKey(MYKEY);

        String result=testService.getkeyFromCache(MYKEY);
        String result2nd=testService.getkeyFromCache(MYKEY);

        verify(testService).getKey(MYKEY);
    }

}

Note: As you are using the Mockito runner - you are not required to initialize Mockito yourself. Also times(1) is a default value for verifying the call.

Question:

I have this production code in my Presenter:

@UiThread
public void tryToReplaceLogo(String emailInitiallySearchedFor, String logoUrl) {
    if(isTheEmailWeAskedApiForStillTheSameAsInTheInputField(emailInitiallySearchedFor)){
        if (!TextUtils.isEmpty(logoUrl)) {
            downloadAndShowImage(logoUrl);
        } else {
            view.displayDefaultLogo();
        }
    }
}

public void downloadAndShowImage(String url) {

    final Target target = new Target() {

        @Override
        public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
            view.displayLogoFromBitmap(bitmap);
        }

        @Override
        public void onBitmapFailed(Drawable errorDrawable) {

        }

        @Override
        public void onPrepareLoad(Drawable placeHolderDrawable) {

        }
    };

    Picasso.with(view.getViewContext()).load(url).resize(150, 150).centerInside().into(target);
}

And this unit test for it:

@Test
public void testDisplayLogoIfValidUrlReturnedAndEmailEnteredIsTheSame() throws Exception {
    when(loginView.getUserName()).thenReturn(VALID_EMAIL);
    when(loginView.getViewContext()).thenReturn(context);
    loginLogoFetcherPresenter.onValidateEmailEvent(createSuccessfulValidateEmailEvent(VALID_EMAIL));
    waitForAsyncTaskToKickIn();
    verify(loginView).displayLogoFromBitmap((Bitmap) anyObject());
}

However, the displayLogoFromBitmap method is never called so my test fails. I need to mock the Target dependency to invoke the onBitmapLoaded method but I don't know how.

Possibly I need to create a static inner class that implements Target so that I can set a Mocked implementation of that in my tests, but how do I invoke the onBitmapLoaded method on the mock?

EDIT:

I have a setter field for Picasso in my LoginPresenter now. In production, (as I am using AndroidAnnotations), I instantiate it in

@AfterInject
void initPicasso() {
    picasso = Picasso.with(context):
}

In my test, I mock Picasso like so:

@Mock
Picasso picasso;

@Before
public void setUp() {
    picasso = mock(Picasso.class, RETURNS_DEEP_STUBS);
}

(I don't remember why, but I can't use Mockito 2 at this point. It was some incompatibility with something, I think)

In my test case, I got to this point and I don't know what to do:

@Test
public void displayLogoIfValidUrlReturnedAndEmailEnteredIsTheSame() throws Exception {
    when(loginView.getUserName()).thenReturn(VALID_EMAIL);
    when(loginView.getViewContext()).thenReturn(context);
    when(picasso.load(anyString()).resize(anyInt(), anyInt()).centerInside().into(???)) // What do I do here?
    loginLogoFetcherPresenter.onValidateEmailEvent(createSuccessfulValidateEmailEvent(VALID_EMAIL));
    waitForAsyncTaskToKickIn();
    verify(loginView).displayLogoFromBitmap((Bitmap) anyObject());
}

Answer:

I need to mock the Target dependency

No; do not mock the system under test. Target is as much a part of that system as anything; you wrote the code for it, after all. Remember, once you mock out a class, you commit to not using its implementation, so trying to mock Target to invoke onBitmapLoaded is missing the point.

What's going on here is that you're passing Target—which is real code you wrote that is worth testing—into Picasso, which is external code you didn't write but do depend on. This makes Picasso the dependency worth mocking, with the caveat that mocking interfaces you don't control can get you into trouble if they change (e.g. a method turns final).

So:

  1. Mock your Picasso instance, and the RequestCreator instance Picasso returns when it loads. RequestCreator implements the Builder pattern, so it's a prime candidate for Mockito 2.0's RETURNS_SELF option or other Builder pattern strategies.
  2. Pass the Picasso instance into your system under test, rather than creating it using Picasso.with. At this point you may not need to stub LoginView.getViewContext(), which is a good thing as your test can interact less with hard-to-test Android system classes, and because you've further separated object creation (Picasso) from business logic.
  3. Use an ArgumentCaptor in your test to extract out the Target method that was called on RequestCreator.into.
  4. Test the state of the system before the async callback returns, if you'd like. It's optional, but it's definitely a state your system will be in, and it's easy to forget to test it. You'd probably call verify(view, never()).onBitmapLoaded(any()).
  5. Call target.onBitmapLoaded yourself. You have the target instance at this point, and it should feel correct to explicitly call your code (that is written in your system-under-test) from your test.
  6. Assert your after-callback state, which here would be verify(view).onBitmapLoaded(any()).

Note that there is an existing test helper called MockPicasso, but it seems to require Robolectric, and I haven't reviewed its safety or utility myself.

Question:

I'm trying to test the code written in callback function of one of Rxjava operator. Here is the original code that I want to test

@Override
public Observable<List<User>> getUsers() {
    UserDataStore userDataStore = userDataStoreFactory.createCloudDataStore();
    return userDataStore.getUsers().map(userEntityDataMapper::transform);
}

In above code there is a "map" operator and its callback Function will transform the original object to another by calling userEntityDataMapper.transform() method. Here I want to test that userEntityDataMapper's transform method must be call. Here is the code which I tried to check if userEntityDataMapper.transform() method calls or not.

@Test
public void testGetUsersHappyCase() {
    List<UserEntity> userEntityList = new ArrayList<>();
    userEntityList.add(new UserEntity());
    given(mockUserDataStore.getUsers()).willReturn(Observable.just(userEntityList));
    List<User> userList = new ArrayList<>();
    given(mockUserEntityDataMapper.transform(userEntityList)).willReturn(userList);
    given(mockUserDataStoreFactory.createCloudDataStore()).willReturn(mockUserDataStore);

    Observable observable = userDataRepository.getUsers();

    verify(mockUserDataStoreFactory).createCloudDataStore();
    verify(mockUserDataStore).getUsers();
    TestObserver<List<UserEntity>> testObserver = new TestObserver<>();
    TestScheduler testScheduler = new TestScheduler();
    observable.subscribeOn(testScheduler).observeOn(testScheduler).subscribeWith(testObserver);
    verify(mockUserEntityDataMapper).transform(any(List.class));
}

I checked many similar questions on stackoverflow and from forum but not able to find exact solution for my question.

Update: Here is the change which I did to fix the problem.

@Test
public void testGetUsersHappyCase() {
    List<UserEntity> userEntityList = new ArrayList<>();
    userEntityList.add(new UserEntity());
    given(mockUserDataStore.getUsers()).willReturn(Observable.just(userEntityList));
    List<User> userList = new ArrayList<>();
    given(mockUserEntityDataMapper.transform(userEntityList)).willReturn(userList);

    userDataRepository.getUsers().test().assertNoErrors();

    verify(mockUserDataStoreFactory).createCloudDataStore();
    verify(mockUserDataStore).getUsers();

    verify(mockUserEntityDataMapper).transform(userEntityList);
}

Thanks @tynn for the hint of test() method. Also same thing I found in BasicRxJavaSample demo found on https://github.com/googlesamples/android-architecture-components.


Answer:

You have to subscribe to the stream in order to execute it. This can be done as easily as calling test() on the observable. This will provide you with a TestObserver.

Additional to this, you don't have any reason to use a TestScheduler. In your case it's actually the issue. You're not calling to triggerActions() and thus your stream is not executed at all.

If you don't modify any scheduler in the code you're testing, just ignore these in your tests as well. If you need to change it, you should better create a rule to set the Schedulers to a synchronous version each. You find setters for this with the RxJavaPlugins class.

Question:

which guru know's the best practice to test the behavier of this class, so that whenever AsyncCallback is called, it should go into onSuccess method. To print out "onSuccess".

@RunWith(MockitoJUnitRunner.class)
public class InterfaceTest {

    @Mock
    private Service service;

    private Employee employee;

    @Before
    public void setUp() throws Exception {
        employee = mock(Employee.class);
    }

    @Test
    public void testMockBehavier() throws Exception {

    }
}

interface AsyncCallback {
    void onError();
    void onSuccess();
}

class Employee {

    @Autowired
    Service service;

    public void save(){
        service.save(new AsyncCallback() {
            @Override
            public void onError() {
                System.out.println("Error");
            }

            @Override
            public void onSuccess() {
                System.out.println("Success");
            }
        });
     }
}

interface Service {
    void save(AsyncCallback asyncCallback);
}

I haven't found out how to access an anonymous inner class. Very appreciate for good practice tipps.

Thanks


Answer:

If I understand correctly, the class under test is Employee. So if there is one class that you should NOT mock, it's Employee.

Second, you need to inject the mock service into the employee under test.

Third, you need to tell the mock service to call the success callback when save() is called.

@RunWith(MockitoJUnitRunner.class)
public class InterfaceTest {

    @Mock
    private Service service;

    @InjectMocks
    private Employee employee;

    @Test
    public void testSuccess() throws Exception {
        Answer<Void> answer = new Answer<Void>() {
            Void answer(InvocationOnMock invocation) {
                AsyncCallback callback = invocation.getArguments()[0];
                callback.onSuccess();
                return null;
            }
        };
        doAnswer(answer).when(service).save(any(AsyncCallback.class));

        employee.save()

        // TODO: now check that the success callback does what it's supposed to do
    }
}

Question:

I am new to unit testing in Android and have gone through several tutorials to get myself familiar with mockito and robolectric.

My app is using Dagger 2 to inject my EventService into my MainActivity. For my MainActivityUnitTest, I have set up a TestServicesModule to provide a mocked version of EventService so that I can use Robolectric to run unit tests against my MainActivity

I'm having an issue getting the ServiceCallback on my EventService.getAllEvents(callback: ServiceCallback) to execute in the unit test. I have verified in the @Setup of my MainActivityUnitTest class that the EventService is being injected as a mocked object. I have gone through several tutorials and blog posts and as far as I can tell, I am doing everything correctly. The refreshData() function in MainActivity is getting called successfully, and I can see that the call to eventsService.getAllEvents(callback) is being executed. But the doAnswer {} lambda function is never getting executed.

Here's my relevant code:

AppComponent.kt

@Singleton
@Component(modules = [
    AppModule::class,
    ServicesModule::class,
    FirebaseModule::class
])
interface AppComponent {
    fun inject(target: MainActivity)
}

ServicesModule.kt

@Module
open class ServicesModule {
    @Provides
    @Singleton
    open fun provideEventService(db: FirebaseFirestore): EventsService {
        return EventsServiceImpl(db)
    }
}

EventsService.kt

interface EventsService {
    fun getAllEvents(callback: ServiceCallback<List<Event>>)
    fun getEvent(id: String, callback: ServiceCallback<Event?>)
}

MainActivity.kt

class MainActivity : AppCompatActivity() {
    @Inject lateinit var eventsService: EventsService

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        (application as App).appComponent.inject(this)
        ...
    }

    override fun onStart() {
        super.onStart()
        refreshData()
    }

    eventsService.getAllEvents(object: ServiceCallback<List<Event>> {
        override fun onCompletion(result: List<Event>) {
            viewModel.allEvents.value = result
            loading_progress.hide()
        }
    })
}

Now we get into the tests:

TestAppComponent.kt

@Singleton
@Component(modules = [
    TestServicesModule::class
])
interface TestAppComponent : AppComponent {
    fun inject(target: MainActivityUnitTest)
}

TestServicesModule.kt

@Module
class TestServicesModule {

    @Provides
    @Singleton
    fun provideEventsService(): EventsService {
        return mock()
    }
}

MainActivityUnitTest.kt

@RunWith(RobolectricTestRunner::class)
@Config(application = TestApp::class)
class MainActivityUnitTest {

    @Inject lateinit var eventsService: EventsService

    @Before
    fun setup() {
        val testComponent = DaggerTestAppComponent.builder().build()
        testComponent.inject(this)
    }

    @Test
    fun givenActivityStarted_whenLoadFailed_shouldDisplayNoEventsMessage() {
        val events = ArrayList<Event>()

        doAnswer {
            //this block is never hit during debug
            val callback: ServiceCallback<List<Event>> = it.getArgument(0)
            callback.onCompletion(events)
        }.whenever(eventsService).getAllEvents(any())

        val activity = Robolectric.buildActivity(MainActivity::class.java).create().start().visible().get()
        val noEventsView = activity.findViewById(R.id.no_events) as View

        //this always evaluates to null because the callback is never set from the doAnswer lambda
        assertThat(callback).isNotNull()
        verify(callback)!!.onCompletion(events)
        assertThat(noEventsView.visibility).isEqualTo(View.VISIBLE)
    }
}

Edit: Adding App and TestApp

open class App : Application() {
    private val TAG = this::class.qualifiedName
    lateinit var appComponent: AppComponent

    override fun onCreate() {
        super.onCreate()
        appComponent = initDagger(this)
    }

    open fun initDagger(app: App): AppComponent {
        return DaggerAppComponent.builder().appModule(AppModule(app)).build()
    }
}

class TestApp : App() {
    override fun initDagger(app: App): AppComponent {
        return DaggerTestAppComponent.builder().build()
    }
}

Answer:

It looks like you're using a different component to inject your test and activity. As they're different components I suspect you are using 2 different instances of the eventsService.

Your test uses a local DaggerTestAppComponent.

@Inject lateinit var eventsService: EventsService

@Before
fun setup() {
    val testComponent = DaggerTestAppComponent.builder().build()
    testComponent.inject(this)
}

While your Activity uses the appComponent from the application.

class MainActivity : AppCompatActivity() {
    @Inject lateinit var eventsService: EventsService

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        (application as App).appComponent.inject(this)
        ...
    }

To overcome this you may consider adding a test version of your application class, this would allow you to replace the AppComponent in your application with your TestAppComponent. Robolectric should allow you to create a test application as follows: http://robolectric.org/custom-test-runner/

Question:

How to mock a method that takes callback object and invoker of this method use it to delegate result to other callback. Here in my scenario I am creating Rx Single from it.

1. RecentDataModel.java

public class RecentDataModel {

public void getRecentData(RecentDataAdapter recentDataAdapter) {
    // Get data from database
    // Invoke if success
    recentDataAdapter.onSuccess()
    // Invoke if error
    recentDataAdapter.onError()

}
}

2. RecentDataAdapter.java

public class RecentDataAdapter {
    onSuccess(List<String> recents);
    onError();
}

3. RecentPresenter

public class RecentPresenter {
public Single<List<String>> getRecentsSingle() {
    return Single.create(new Single.OnSubscribe<List<String>>() {
            @Override
            public void call(final SingleSubscriber<? super List<String>> singleSubscriber) {
                mRecentDataModel.getRecentData(new RecentDataAdapter() {
                    @Override
                    public void onSuccess(List<String> keywordList) {
                        singleSubscriber.onSuccess(keywordList);
                    }
                });
            }
        });
}
}

4. RecentTestCase

public class RecentPresenterTest {

    @Mock
    RecentDataModel recentModel;

    @Test
    public void testLoadRecent() {
        doAnswer(new Answer() {
            @Override
            public List<String> answer(InvocationOnMock invocation) throws Throwable {
                List<String> recents = new ArrayList<>();
                recents.add("Recent1");
        recents.add("Recent2");
                return recents;
            }
        }).when(recentModel).getRecentData(any(RecentDataAdapter.class));

        RecentPresenter recentProvider = new RecentPresenter(null, null, prefModel);

        Action1 onNextListener = mock(Action1.class);

        recentProvider.getRecentsSingle.subscribe(onNextListener);

        ArgumentCaptor<List<String>> listCaptor = ArgumentCaptor.forClass((Class) List.class);

        verify(onNextListener, timeout(5000)).call(listCaptor.capture());
        assertNotNull(listCaptor.getValue());
        assertEquals(listCaptor.getValue().get(0), "Recent1");
    }

}

Note:

  1. Not having access to RecentDataModel and hence can't introduce new method like: List<String> getRecentData();

  2. Although method ResentPresenter.getRecentsSingle() is not doing any business logic. But it gets connected with other methods in the class to produce the output. So mocking RecentDataModel is necessary.

  3. Test is failing in following line "verify(onNextListener, timeout(5000)).call(listCaptor.capture());" because while mocking I am providing any(RecentDataAdapter.class) due to which singleSubscriber.onSuccess(keywordList); never gets called.


Answer:

The issue is that you don't call your callback on your adapter. As the callback is never called, Single.success is never called. So the Single is not notified to the emited list. And then your verify timeout.

To fix the issue, you have to call the onSuccess callback method in your mock :

  doAnswer(new Answer() {
        @Override
        public Void answer(InvocationOnMock invocation) throws Throwable {
            List<String> recents = new ArrayList<>();
            recents.add("Recent1");
            recents.add("Recent2");
            invocation.getArguments()[0].onSuccess(recents);
            return null;
        }
 }).when(recentModel).getRecentData(any(RecentDataAdapter.class));

Question:

I'm pretty new in unit testing and dont know how to test the following circunstances over a callback for this example class:

public class Foo {

    private final ItemLoader loader;
    private Bar bar;

    public Foo(ItemLoader loader,Bar bar) {
        super();
        this.loader = loader;
        this.bar=bar;
    }

    public void getItems(ItemStore.Callback callback) {
        List<ItemData> itemData = bar.getItemData();
        List<Item> items = this.loader.transform(itemData);
        callback.onItemsLoaded(items);
    }

}
  • That callback.onItemsLoaded is called with the result of loader.transform

My current test is:

public class ExampleTest extends BaseTestCase {

    private Foo foo;

    @Mock
    private Bar mockBar;

    @Mock
    private ItemLoader mockItemLoader;

    @Mock
    private ItemStore.Callback itemLoadCallback;

    public void setUp() {
        MockitoAnnotations.initMocks(this);
        foo = new Foo(mockItemLoader, mockBar);
    }

    public void testGetItems() {
        List<ItemData> mockItemData = (List<ItemData>) mock(List.class);
        when(mockBar.getItemData()).thenReturn(mockItemData);
        foo.getItems(itemLoadCallback);
        verify(mockItemLoader).transform(mockItemData);
    }

}

It tests:

  • That loader.transform is called
  • That callback.onItemsLoaded is called

But I realised that if I change the last line of the Foo.getItems method like (Notice the null):

    public void getItems(ItemStore.Callback callback) {
        ...
        callback.onItemsLoaded(null);
    }

The test keep pasing. So I'd need to test that callback.onItemsLoaded is called with the result of loader.transform So I modified the test:

    public void testGetItems() {
        List<ItemData> mockItemData = (List<ItemData>) mock(List.class);
        when(mockBar.getItemData()).thenReturn(mockItemData);
        foo.getItems(itemLoadCallback);
        verify(mockItemLoader).transform(mockItemData);
        List<Item> resultItems = verify(mockItemLoader).transform(mockItemData);
        verify(itemLoadCallback).onItemsLoaded(resultItems);
    }

But it complains in the last line saying Argument(s) are different!

How can I fix the test


Answer:

Because mockItemLoader is a mock, it will actually return an empty list from transform. If you want to make it return something different, you could set up an object for it to return. Basically, this will be your own List<Item>. So you can then stub the tranform method instead of verifying it; and use the same List<Item> when you verify the call to onItemsLoaded.

Question:

I have very basic service with method post that updates it's progress via callback interface.

public class HttpPostService {
    public interface UploadingProgressListener {
        void onProgress(int progress);
    }

    public int post(InputStream body, UploadingProgressListener listener)
    {
         // shortened for brevity
         // read inputstream and writes bytes to HttpURLConnection outputstream
         // read inputstream in loop notify listener about progress
         listener.onProgress(percentage);
    }
}

I would like to test this class with Mockito, basically mock UploadingProgressListener and then check if it was called n-times with correct percentage arguments.

@Test
public void testPostFileProgressListener() throws IOException {
    UploadingProgressListener mockListener = mock(UploadingProgressListener.class);

    InputStream inputStream = new ByteArrayInputStream();
    service.postFile(inputStream, mockListener);
    verify(mockListener, times(5)).onProgress(100);
}

However when I run test it says it was only invoked one time, but when I debug it listener was called 5 times.

I know there is concept of Answers and ArgumentCaptors, but I thought at least counting how many times mock was called would be correct. Thanks for any help.


Answer:

If you indeed want to check that there was an ordered sequence of 5 calls, with 20, 40, 60, 80 and 100 as argument, you just need

    InOrder inOrder = inOrder(mockListener);
    inOrder.verify(mockListener).onProgress(20);
    inOrder.verify(mockListener).onProgress(40);
    inOrder.verify(mockListener).onProgress(60);
    inOrder.verify(mockListener).onProgress(80);
    inOrder.verify(mockListener).onProgress(100);

If you just want to check that the listener has been called 5 times, without caring about the arguments, then just use

    verify(mockListener, times(5)).onProgress(anyInt());

Question:

I am testing the interaction with a socket I have mocked the socket, and want to test that something happened in the ack, for that I need to have the ack called.

I tried to write the following :

        Answer<Void> answer = invocation -> {
            Ack ack = invocation.getArgument(2);
            ack.call(any(Object[].class));
            return null;
        };
        doAnswer(answer).when(socket).emit(anyString(),any(Object[].class),any(Ack.class));

However, when in my code, my mock socket does socket.emit("blahblah","bababa",Ack);

The answer is not invoked.

How to make it work ?


Answer:

According to the mock expectation, the second argument to emit is an Object[] ...

doAnswer(answer).when(socket).emit(anyString(),any(Object[].class),any(Ack.class));

See: any(Object[].class)

But in your post you state:

my mock socket does socket.emit("blahblah","bababa",Ack);

So you pass a String ("bababa") for the second parameter. This will not match with the Object[] expectation.

If you change your mock expectation to ...

doAnswer(answer).when(socket).emit(anyString(), anyString(), any(Ack.class));

... then the invocation should match.

Question:

I have method and need to test it:

void update() {
    _cleaner.clear();
    _updator.upadate();
}

The ordering of calls is important for this scenario. I want to write test like this:

void updateTest(){

   Integer CLEAR = 0, UPDATE = 1;
   Stack<Integer> callStack = new Stack<>();

   Cleaner cleaner = mock(Cleaner.class);
   Updator updator = mock(Updator.class);

   when(cleaner.clear()).callback(() -> callStack.add(CLEAR)); 
   when(updator.update()).callback(() -> callStack.add(UPDATE));

   Some testingObj = new Some(cleaner, updator);
   testingObj.update();

   assertEquels(CLEAR, callStack.pop());
   assertEquels(UPDATE, callStack.pop());
   assertTrue(callStack.isEmpty());
}

_cleaner.clear() and _updator.upadate() returns void. It is clear that

when(cleaner.clear()).callback(() -> callStack.add(ClearCall)); 
when(updator.update()).callback(() -> callStack.add(UpdateCall));

is invalid code. What can I write except those lines for success? How to setup callback for method (with void as type of result) call by mockito?


Answer:

I recommend you use the InOrder verifier to confirm that the methods are called in the order you want. See here for some of the documentation: http://site.mockito.org/mockito/docs/current/org/mockito/InOrder.html

This example is based on code straight from that documentation:

InOrder inOrder = inOrder(cleaner, updator);

inOrder.verify(cleaner).clear();
inOrder.verify(updator).update();

Question:

I'm trying to debug the inner success callback of an RxJava Subscription object and verify certain methods inside that get called with the correct argument(s). I read up some about Captors and though maybe that's the way to go but was unable to find an example that matched my needs.

I'm unit testing with: Mockito and JUnit

// OrderHistoryPresenterImpl presenter;
public void loadOrderHistory(final int offset, final int limit) {
    mCompositeSubscription.add(useCase.getOrderHistory(offset, limit)
            .doOnError(throwable -> Timber.e(throwable, "Error"))
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Subscriber<ListOfOrders>() {
                @Override
                public void onCompleted() {}

                @Override
                public void onError(Throwable e) {}

                @Override
                public void onNext(ListOfOrders listOfOrders) {
                    //
                    // I would like to verify the calls in this method
                    //
                    user.setTryoutCountActive(listOfOrders.getActiveTryoutsCount());

                    getView().addOrdersToView(listOfOrders);

                    mCompositeSubscription.clear();
                }
            })
    );
}

And here are the tests I'm trying to test it with

@RunWith(MockitoJUnitRunner.class)
public class OrderHistoryPresenterTest {
    // Boiler plate Dagger 2 setup + variable declarations

    private ListOfOrders response;
    private ListOfOrders spyListOfOrders;
    private OrderHistoryPresenterImpl presenter;
    @Mock private OrderHistoryUseCaseImpl useCase;

    @Before
    public void setUp() throws FileNotFoundException {
        // Setup + dagger 2 setup…

        response = Utils.fromJson(gson, this, "OrderHistory.json", type);
        spyListOfOrders = spy(response);

        presenter = new OrderHistoryPresenterImpl(app, useCase, user);

        when(useCase.getOrderHistory(MOCK_USER_ACCESS_TOKEN)).thenReturn(Observable.just(spyListOfOrders));
    }

    @After
    public void tearDown() {…}

    @Test
    public void shouldGetOrderAndCall_addOrdersToView_OnActivity() {
        presenter.loadOrderHistory(MOCK_OFFSET, MOCK_LIMIT);

        // works…
        verify(useCase, times(1)).getOrderHistory(MOCK_USER_ACCESS_TOKEN);

        // This fails because it gets called right away because it's async - what to do?
        verify(view, times(1)).addOrdersToView(spyListOfOrders);
    }
}

So as you can see I don't know how to test the inner Subscriber<ListOfOrders> callback methods. Any help would be greatly appreciated!


Answer:

Let's say if you rewrite your method like this,

// OrderHistoryPresenterImpl presenter;
public void loadOrderHistory(final int offset, final int limit) {
  mCompositeSubscription.add(useCase.getOrderHistory(offset, limit)
        .doOnError(throwable -> Timber.e(throwable, "Error"))
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Subscriber<ListOfOrders>() {
            @Override
            public void onCompleted() {}

            @Override
            public void onError(Throwable e) {}

            @Override
            public void onNext(ListOfOrders listOfOrders) {
               load(listOfOrders)
            }
        })
   );
 }

 void loadOrders(ListOfOrders list) {
     // I would like to verify the calls in this method
     user.setTryoutCountActive(listOfOrders.getActiveTryoutsCount());

     getView().addOrdersToView(listOfOrders);

     mCompositeSubscription.clear();
 }

Now test this loadOrders method separately. Because all it cares about is getting a list of orders to process. It can come from anywhere (not only observable).

You can unit test this method now.

If you want to test Observable, then use TestSubscriber to see if you are actually getting a list of orders from Observable. Ref : https://reactivex.io/RxJava/javadoc/rx/observers/TestSubscriber.html‌​

Question:

I successfully did some tests of asynchronous function with only one callback interface as parameter with mockito-kotlin library but when I try to do a test of same function with another parameter like a String or Integer I receive error:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException:

Invalid use of argument matchers!

2 matchers expected, 1 recorded:

-> at com.example.presentation.presenter.MyCollectionPresenterTest.getComicListByHeroOK(MyCollectionPresenterTest.kt:97)

This exception may occur if matchers are combined with raw values:

//incorrect:

someMethod(anyObject(), "raw String");

When using matchers, all arguments have to be provided by matchers.

For example:

//correct:

someMethod(anyObject(), eq("String by matcher"));

For more info see javadoc for Matchers class.

I´m sure I´m mocking properly callback interface with any() but I don´t know if I´m mocking integer parameter correctly. I tried with any(), anyInt(), eq(1) and any() as Int but always the same error.

Here is the class that I want to test:

@PerFragment
class MyCollectionPresenter @Inject constructor(private val useCase: GetComicListByHeroUseCase) {

    @Inject
    lateinit var view: MyCollectionView
    lateinit var models: List<ComicModel>

    fun getComicListByHero(heroId: Int) {
        useCase.execute(heroId, object : HeroUseCase.GetComicListByHeroCallback {
            override fun onComicListReceived(comicList: List<Comic>) {
                models = ComicModelMapper.toModel(comicList)
                view.setItems(models)
            }

            override fun onError() {
                view.showMessage()
            }

        })
    }
}

And this is the test class:

class MyCollectionPresenterTest : UnitTest() {

    private lateinit var presenter: MyCollectionPresenter
    @Mock
    private lateinit var useCase: GetComicListByHeroUseCase
    @Mock
    private lateinit var view: MyCollectionView

    @Before
    fun setUp() {
        presenter = MyCollectionPresenter(useCase)
        initializeView()
    }

    @Test
    fun getComicListByHeroOK() {
        setupGetComicsCallbackOK()

        presenter.getComicListByHero(any())

        verify(presenter.view).setItems(emptyList())
    }

    @Test
    fun getComicListByHeroError() {
        setupGetComicsCallbackError()

        presenter.getComicListByHero(any())

        verify(presenter.view).showMessage()
    }

    private fun initializeView() {
        presenter.view = view
    }

    private fun setupGetComicsCallbackError() {
        doAnswer {
            val callback = it.arguments[0] as HeroUseCase.GetComicListByHeroCallback
            callback.onError()
            null
        }.`when`(useCase).execute(any(), any())
    }

    private fun setupGetComicsCallbackOK() {
        doAnswer {
            val callback = it.arguments[0] as HeroUseCase.GetComicListByHeroCallback
            callback.onComicListReceived(emptyList())
            null
        }.`when`(useCase).execute(any(), any())
    }
}

This is base unit test class:

@RunWith(MockitoJUnitRunner::class)
abstract class UnitTest {

    @Suppress("LeakingThis")
    @Rule
    @JvmField
    val injectMocks = InjectMocksRule.create(this@UnitTest)
}

And this is a class for inject mocks rule:

class InjectMocksRule {

    companion object {
        fun create(testClass: Any) = TestRule { statement, _ ->
            MockitoAnnotations.initMocks(testClass)
            statement
        }
    }
}

Thank you very much for your help and excuse my english.

Regards!

UPDATE: I found the solution and posted as answer.


Answer:

Finally, I know what I was doing wrong. First at all, it.argument[1] because callback is the second parameter of the function that I want to mock the answer.

And the other thing is that I was mocking the parameter of the function that I want to test presenter.getComicListByHero(1).

Here is the revised code:

@Test
fun getComicListByHeroError() {
    setupGetComicsCallbackError()

    presenter.getComicListByHero(1)

    verify(presenter.view).showMessage()
}

private fun setupGetComicsCallbackError() {
    doAnswer {
        val callback = it.arguments[1] as HeroUseCase.GetComicListByHeroCallback
        callback.onError()
        null
    }.`when`(useCase).execute(ArgumentMatchers.anyInt(), any())
}

Thank you very much to @voghDev for his help