1

First time unit testing, and using Mockito. I'm not sure if I'm thinking about testing this correctly. Here is the situation:

In my Android app, I am using Model-View-Presenter. I am trying to test a method in my presenter class called validateCredential(serviceManager: ServiceManager, email: String, password: String) to see if the service manager I pass to it will eventually call a callback (this method is called by the view) by verifying it with mockito.

// method in presenter class
override fun validateCredential(serviceManager: ServiceManager, email: String, password: String) {
    loginModel = LoginModel(email, password)
    serviceManager.getParent(email, password)
    serviceManager.execute()
}

// callback implemented by presenter class
private fun handleLoginResult(result: ServiceManager.RequestResult, data: ByteArray, responseCode: Int, optionalParam: String) {
    ...
    mView.startHomeScreen()
}

The presenter class also implements a callback interface (IServiceAsyncTaskCallback) that is provided to the serviceManager's constructor. What I want in this specific unit test is to verify that mView.startHomeScreen() is called.

The problem:

  • Android unit testing seems to require that ServiceManager be mocked (ServiceManager extends abstract class AsyncTask) because when I call execute(), the Android unit testing lib will throw an exception if it is not mocked.
  • However, if I mock the ServiceManager, I can't provide it with two necessary parameters to the constructor, which SHOULD be mocked, if I'm understanding unit testing correctly. The two parameters to the constructor are an interface callback (which is the presenter class), and a class object that is responsible for sending JSON through http. Both of these should be mocked, correct? Because in a unit test you don't want these dependencies to actually make HTTP calls or call callbacks, right?
  • It seems I'm overthinking this. What I really want is to see if my view object which is passed to presenter, calls startHomeScreen(), so I should really just forget testing the validateCredentialMethod() and just call handleLoginResult(...) directly. Is this better than the above route?
  • However, another problem is that even if I call handleLoginResult(...) directly to test if the mock view that is passed to presenter is called, that method code contains a call to JSONObject which is Android related code, and since it belongs to the android.jar file, it will throw an exception because it is not mocked! Am I supposed to provide an injection for that too?!

I'm lost as how to test this. What's the correct way to verify that the mock view has called startHomeScreen()?

ShrimpCrackers
  • 4,388
  • 17
  • 50
  • 76
  • just posted an answer to this... if that answers your question, you might want to edit the title, as I think it doesn't reflect your real problem – marianosimone Nov 16 '17 at 07:13

1 Answers1

1

The problem is that you are trying to test two separate classes in one unit test, which makes it not a unit test.

With your current setup, it seems like you want to have 3 different test cases, in 2 different classes (making up names, trying to be as explicit as possible about their content):

  • PresenterTest

    • testThatServiceManagerIsExcecutedOnValidateCredential
    • testThatStartHomeScreenIsCalledWhenHandlingLoginResult
  • ServiceManagerTest

    • testCallbackIsCalledOnExcecuted
marianosimone
  • 3,366
  • 26
  • 32
  • Ok. Makes sense. For `testCallbackIsCalledOnExecuted()`, how would I handle the call to the `JSONObject()` constructor that throws an exception (since it belongs to android.jar)? Do I have to inject that as a mock somewhere? If so, it seems like there could be an endless amount of mocks whenever I'm calling something that belongs to the test version of android.jar. – ShrimpCrackers Nov 16 '17 at 07:38
  • I'd need a bit more context on what your `ServiceManager` does. In general, what you can do is wrap your calls to Android methods in your own classes, and then you can mock does (e.g. create a JSONObjectFactory, which calls JSONObject(), but in tests mock it to do whatever you want. – marianosimone Nov 16 '17 at 07:51
  • for cases where you are calling static methods in Android, you coul duse PowerMockito: https://stackoverflow.com/questions/21105403/mocking-static-methods-with-mockito – marianosimone Nov 16 '17 at 07:51