Hot questions for Using Mockito in mvp

Question:

Android Studio 2.1.2

I want to test that the callbacks onUsernameError, onPasswordError, and onSuccess, in the LoginModelImp are actually called. I am not sure how to test event listeners. However, the test fails as those functions are never called. I am mocking them with mockito and trying to verify them.

This is my code so far.

Presenter interface

public interface LoginPresenterContract<LoginFragmentViewContract> {
    void validateCredentials();

    void attachView(LoginFragmentViewContract view);
    void detachView();
}

Presenter implementation

public class LoginPresenterImp implements LoginPresenterContract<LoginFragmentViewContract>, LoginModelContract.OnLoginCompletedListener {

    private LoginModelContract mLoginModelContract;
    private LoginFragmentViewContract mLoginFragmentView;

    public LoginPresenterImp(LoginModelContract loginModelContract) {
        mLoginModelContract = loginModelContract;
    }

    /*
     * LoginPresenterContact - implementation
     */
    @Override
    public void attachView(LoginFragmentViewContract view) {
        mLoginFragmentView = view;
    }

    @Override
    public void detachView() {
        mLoginFragmentView = null;
    }

    @Override
    public void validateCredentials() {
        if(mLoginModelContract != null) {
            mLoginModelContract.login(
                    mLoginFragmentView.getUsername(),
                    mLoginFragmentView.getPassword(),
                    LoginPresenterImp.this);
        }
    }

    /*
     * LoginModelContract.OnLoginCompletedListener - implementation
     */
    @Override
    public void onUsernameError() {
        if(mLoginFragmentView != null) {
            mLoginFragmentView.onLoginFailed("Incorrect username");
        }
    }

    @Override
    public void onPasswordError() {
        if(mLoginFragmentView != null) {
            mLoginFragmentView.onLoginFailed("Incorrect password");
        }
    }

    @Override
    public void onSuccess() {
        if(mLoginFragmentView != null) {
            mLoginFragmentView.onLoginSuccess();
        }
    }
}

Model interface

public interface LoginModelContract {
    interface OnLoginCompletedListener {
        void onUsernameError();
        void onPasswordError();
        void onSuccess();
    }
    void login(String username, String password, OnLoginCompletedListener onLoginCompletedListener);
}

Model Implementation

public class LoginModelImp implements LoginModelContract {
    /* Testing Valid username and passwords */
    private static String validUsername = "steve";
    private static String validPassword = "1234";

    @Override
    public void login(final String username,
                      final String password,
                      final OnLoginCompletedListener onLoginCompletedListener) {

        boolean hasSuccess = true;
        if(TextUtils.isEmpty(username) || !username.equals(validUsername)) {
        /* TEST onUsernameError() */
            onLoginCompletedListener.onUsernameError();
            hasSuccess = false;
        }

        if(TextUtils.isEmpty(password) || !password.equals(validPassword)) {
        /* TEST onPasswordError() */
            onLoginCompletedListener.onPasswordError();
            hasSuccess = false;
        }

        if(hasSuccess) {
        /* TEST onSuccess() */
            onLoginCompletedListener.onSuccess();
        }
    }
}

JUnit4 test with Mockito

public class LoginPresenterImpTest {
    private LoginFragmentViewContract mMockViewContract;
    private LoginModelContract mMockModelContract;
    private LoginModelContract.OnLoginCompletedListener mMockOnLoginCompletedListener;
    private LoginPresenterContract<LoginFragmentViewContract> mLoginPresenterContract;

    @Before
    public void setUp() throws Exception {
        mMockViewContract = Mockito.mock(LoginFragmentViewContract.class);
        mMockModelContract = Mockito.mock(LoginModelContract.class);
        mMockOnLoginCompletedListener = Mockito.mock(LoginModelContract.OnLoginCompletedListener.class);
        mLoginPresenterContract = new LoginPresenterImp(mMockModelContract);
        mLoginPresenterContract.attachView(mMockViewContract);
    }

    @Test
    public void shouldSuccessWithValidCredentials() {
        when(mMockViewContract.getUsername()).thenReturn("steve");
        when(mMockViewContract.getPassword()).thenReturn("1234");

        mLoginPresenterContract.validateCredentials();

        verify(mMockViewContract, times(1)).getUsername();
        verify(mMockViewContract, times(1)).getPassword();

        verify(mMockOnLoginCompletedListener, times(1)).onSuccess();

        verify(mMockOnLoginCompletedListener, never()).onPasswordError();
        verify(mMockOnLoginCompletedListener, never()).onUsernameError();
    }
}

Is there any way to test this implementation?

Many thanks for any suggestions,


Answer:

The test class LoginPresenterImpTest is about the test of LoginPresenterImp class, and it should use only its actual implementation and the mocks of its collaborators. The class LoginModelContract.OnLoginCompletedListener is a collaborator of LoginModelImp, so in a well designed, and pure unit-test of LoginPresenterImp, like yours, it's perfectly normal that it is never called. The solution I propose is to test the LoginModelImp separately:

public class LoginModelImpTest {

    private LoginModelContract.OnLoginCompletedListener mMockOnLoginCompletedListener;
    private LoginModelImp loginModelImp;

    @Before
    public void setUp() throws Exception {
        mMockOnLoginCompletedListener = Mockito.mock(LoginModelContract.OnLoginCompletedListener.class);
        loginModelImp = new LoginModelImp();
    }

    @Test
    public void shouldSuccessWithValidCredentials() {

        loginModelImp.login("steve", "1234", mMockOnLoginCompletedListener);;

        verify(mMockOnLoginCompletedListener, times(1)).onSuccess();

        verify(mMockOnLoginCompletedListener, never()).onPasswordError();
        verify(mMockOnLoginCompletedListener, never()).onUsernameError();
    }
}

Alternatively, you have to use the actual implementation of LoginModelImp in your LoginPresenterImpTest and spy on your listener (that is the presenter itself) or to configure the mocks to make them call the listener. Here's an example, but I wouldn't use this one:

public class LoginPresenterImpTest {
    private LoginFragmentViewContract mMockViewContract;
    private LoginModelContract mModelContract;
    private LoginModelContract.OnLoginCompletedListener mMockOnLoginCompletedListener;
    private LoginPresenterContract<LoginFragmentViewContract> mLoginPresenterContract;

    @Before
    public void setUp() throws Exception {
        mMockViewContract = Mockito.mock(LoginFragmentViewContract.class);
        mModelContract = new LoginModelImp();
        LoginPresenterImp spyPresenterImp = Mockito.spy(new LoginPresenterImp(mModelContract));
        mLoginPresenterContract = spyPresenterImp;
        mMockOnLoginCompletedListener = spyPresenterImp;
        mLoginPresenterContract.attachView(mMockViewContract);
    }

    @Test
    public void shouldSuccessWithValidCredentials() {
        when(mMockViewContract.getUsername()).thenReturn("steve");
        when(mMockViewContract.getPassword()).thenReturn("1234");

        mLoginPresenterContract.validateCredentials();

        verify(mMockViewContract, times(1)).getUsername();
        verify(mMockViewContract, times(1)).getPassword();

        verify(mMockOnLoginCompletedListener, times(1)).onSuccess();

        verify(mMockOnLoginCompletedListener, never()).onPasswordError();
        verify(mMockOnLoginCompletedListener, never()).onUsernameError();
    }
}

Question:

I follow the MVP pattern + UseCases to interact with a Model layer. This is a method in a Presenter I want to test:

fun loadPreviews() {
    launch(UI) {
        val items = previewsUseCase.getPreviews() // a suspending function
        println("[method] UseCase items: $items")

        println("[method] View call")
        view.showPreviews(items)
    }
}

My simple BDD test:

fun <T> givenSuspended(block: suspend () -> T) = BDDMockito.given(runBlocking { block() })

infix fun <T> BDDMockito.BDDMyOngoingStubbing<T>.willReturn(block: () -> T) = willReturn(block())

@Test
fun `load previews`() {
    // UseCase and View are mocked in a `setUp` method

    val items = listOf<PreviewItem>()
    givenSuspended { previewsUseCase.getPreviews() } willReturn { items }

    println("[test] before Presenter call")
    runBlocking { presenter.loadPreviews() }
    println("[test] after Presenter call")

    println("[test] verify the View")
    verify(view).showPreviews(items)
}

The test passes successfully but there's something weird in the log. I expect it to be:

  • "[test] before Presenter call"
  • "[method] UseCase items: []"
  • "[method] View call"
  • "[test] after Presenter call"
  • "[test] verify the View"

But it turns out to be:

  • [test] before Presenter call
  • [test] after Presenter call
  • [test] verify the View
  • [method] UseCase items: []
  • [method] View call

What's the reason of this behaviour and how should I fix it?


Answer:

I see you found out on you own, but I'd like to explain a bit more for the people that might run into the same problem

When you do launch(UI) {}, a new coroutine is created and dispatched to the "UI" Dispatcher, that means that your coroutine now runs on a different thread.

Your runBlocking{} call create a new coroutine, but runBlocking{} will wait for this coroutine to end before continuing, your loadPreviews() function creates a coroutine, start it and then return immediately, so runBlocking() just wait for it and return.

So while runBlocking{} has returned, the coroutine that you created with launch(UI){} is still running in a different thread, that's why the order of your log is messed up

The Unconfined context is a special CoroutineContext that simply create a dispatcher that execute the coroutine right there on the current thread, so now when you execute runBlocking{}, it has to wait for the coroutine created by launch{} to end because it is running on the same thread thus blocking that thread.

I hope my explanation was clear, have a good day

Question:

I am learning Android MVP architecture and trying to test some methods with Mockito/JUnit. I was learning from this tutorial:

https://codelabs.developers.google.com/codelabs/android-testing/index.html?index=..%2F..%2Findex

I have a problem with testing the Presenter method in my Android MVP architecture type app.

Here is my Presenter class:

public class ForgotPasswordPresenter implements ForgotPasswordMVP.Presenter{
private ForgotPasswordMVP.View view;
private ForgotPasswordMVP.Model model;


public ForgotPasswordPresenter(FirebaseAuthService firebaseAuthService, ForgotPasswordMVP.Model model) {
    this.model = model;
}

@Override
public void setView(ForgotPasswordMVP.View view) {
    this.view = view;
}

@Override
public void sendButtonClicked() {

    if(view != null) {
        view.showProgressBar();
        model.sendEmail(view.getEmail(), new 
        ForgotPasswordMVP.Model.SendForgotEmailCallback() {
            @Override
            public void onEmailSent(boolean sent) {
                if(sent) {
                    view.hideProgressBar();
                    view.showEmailSent();
                }
                else{
                //show some error on UI
                }
            }
        });
    }
  }
}

Here is the contract interface for the MVP.Model structure. I defined custom Callback:

   interface Model{
   interface SendForgotEmailCallback {
        void onEmailSent(boolean sent);
    }

    void sendEmail(String email, @NonNull SendForgotEmailCallback SendForgotEmailCallback) ;
}

In my model i do stuff like this, I am just using Firebase to reset the password:

public class ForgotPasswordModel implements ForgotPasswordMVP.Model{

private FirebaseAuthService firebaseAuthService;

public ForgotPasswordModel(FirebaseAuthService firebaseAuthService) {
    this.firebaseAuthService = firebaseAuthService;
}

@Override
public void sendEmail(String email, @NonNull final SendForgotEmailCallback SendForgotEmailCallback) {
    firebaseAuthService.sendPasswordResetEmail(email).addOnCompleteListener(new OnCompleteListener<Void>() {
        @Override
        public void onComplete(@NonNull Task<Void> task) {
                if(task.isSuccessful()){
                    SendForgotEmailCallback.onEmailSent(true);
                }
                else{
                    SendForgotEmailCallback.onEmailSent(false);
                }
        }
    });
}
}

Now, I want to test the method responsible for sending the Email, just the send button clicked. Here is my test prototype:

public class ForgotPasswordPresenterTest {

@Mock
ForgotPasswordMVP.Model model;

@Mock
ForgotPasswordMVP.View view;

@Mock
FirebaseAuthService firebaseAuthService;

@Captor
private ArgumentCaptor<ForgotPasswordMVP.Model.SendForgotEmailCallback> sendForgotEmailCallbackArgumentCaptor;


private ForgotPasswordPresenter forgotPasswordPresenter;

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

    forgotPasswordPresenter = new ForgotPasswordPresenter(firebaseAuthService, model);
    forgotPasswordPresenter.setView(view);
}

  @Test
public void sendButtonClicked_shouldShowEmailSent(){

    when(view.getEmail()).thenReturn("test@mail.com");

    forgotPasswordPresenter.sendButtonClicked();

    verify(model).sendEmail(view.getEmail(), sendForgotEmailCallbackArgumentCaptor.capture());
    sendForgotEmailCallbackArgumentCaptor.getValue().onEmailSent(true);

    verify(view).showEmailSent();

}

}

So, when it comes to verify(model).sendEmail... it crashes and this Exception from Mockito comes up:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Invalid use of argument matchers! 2 matchers expected, 1 recorded: -> at com.example.app.ui.login.ForgotPasswordPresenterTest.sendButtonClicked_shouldShowEmailSent(ForgotPasswordPresenterTest.java:53) 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.

Can anyone help me with this? I am beginner, trying to figure it out, but really don't have a clue for now.


Answer:

Since you are capturing the argument using capture() (which is treated as a matcher), you have to use eq for all the other raw values in your verify. In your test view.getEmail() returns raw value ("test@mail.com"), so your verify would change to this :

verify(model).sendEmail(eq(view.getEmail()), sendForgotEmailCallbackArgumentCaptor.capture());

Notice that you will now verify view.getEmail() wrapped with eq.

A good thing to remember is : If you use a matcher for any of the method arguments, then all arguments should be verified with matchers (use eq for raw values).

Question:

I have a very simple app built using MVP pattern. This is my Contract:

public interface CitiesContract {
    interface View {
        void addCitiesToList(List<City> cityList);
    }

    interface Presenter {
        void getCityList();
    }

    interface Model {
        List<City> getCityList();
    }
}

This is my View:

public class CitiesActivity extends AppCompatActivity implements CitiesContract.View {
    private List<City> cityList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_cities);

        CitiesPresenter presenter = new CitiesPresenter(this);
        presenter.getCityList();
    }

    @Override
    public void addCitiesToList(List<City> cities) {
        cityList.addAll(cities);
    }
}

This is my Presenter:

public class CitiesPresenter implements CitiesContract.Presenter {
    private CitiesContract.View view;
    private CitiesModel model;

    public CitiesPresenter(CitiesContract.View view) {
        this.view = view;
        model = new CitiesModel();
    }

    @Override
    public void getCityList() {
        List<City> cityList = model.getCityList();
        view.addCitiesToList(cityList);
    }
}

This is my Model:

public class CitiesModel implements CitiesContract.Model {
    @Override
    public List<City> getCityList() {
        List<City> cityList = new ArrayList<>();
        //Add 30 cities to the list
        return cityList;
    }
}

How can I test the getCityList() method within my Presenter? This is what I have tried so far:

public class CitiesPresenterTest {
    private CitiesContract.Presenter citiesPresenter;
    @Mock
    private CitiesContract.View citiesView;

    public void setUp() {
        MockitoAnnotations.initMocks(this);
        citiesPresenter = new CitiesPresenter(citiesView);
    }

    @Test
    public void getCityListTest() {
        citiesPresenter.getCityList();
        //What to do next???
    }
}

Answer:

Ok, that's a good question btw. First of all you also need to mock you model. Second: arrange something: for example that model.getCityList() return null. After that you can verify using mockitos verify operator. Example:

when(model.getCityList()).thenReturn(null);
citiesPresenter.getCityList();
verify(view).addCitiesToList(null);

Another case can be just like that, but with an empty list:

List<City> citiesList = new ArrayList<>();

when(model.getCityList()).thenReturn(citiesList );
citiesPresenter.getCityList();
verify(view).addCitiesToList(citiesList);

And another one can be just like that, with a fake List you can build on your own just to test it:

List<City> citiesList = new ArrayList<>();
list.add(City("name", "something else", "i don't know what atributes you have"));

when(model.getCityList()).thenReturn(citiesList );
citiesPresenter.getCityList();
verify(view).addCitiesToList(citiesList);

Hope I helped.

Additional information: When unit testing you should have 3 basic steps in your head: First you Arrange: So you create your own scenario.Example what if list is null. Second: you Act: this step is where you test the method you want. Third: Assert: this is where you verify or assert that your expectations match with given code.

Question:

I think somethings wrong about my code in TeamImplsTest, and i need advice :D This is my code

API interface

interface API { @GET("lookupteam.php") fun getTeam(@Query("id") id: String): Call<TeamModel> }

TeamPresenter

interface MatchPresenter { fun loadTeamDetail(team_id: String) }

TeamImpls

class TeamImpls(val teamView: TeamView) : TeamPresenter {

    override fun loadTeamDetail(team_id: String) {
        val call = RetrofitConfig().getApi().getTeam(team_id)
        call.enqueue(object : Callback {
            override fun onResponse(call: Call, response: Response) {
                if (response.isSuccessful()) {
                    val res = response.body()
                    res?.let { teamView.onSuccess(it) }
                }
            }

            override fun onFailure(call: Call, t: Throwable) {
                Log.e("PrevMatchFragment", t.toString())
            }
        })
    }
}

TeamModel

data class TeamModel(
        val teams: ArrayList
)

data class TeamModeLResult(
        val idTeam: String,
        val strTeam: String,
        val strAlternate: String,
        val strSport: String,
        val strStadium: String,
        val strTeamBadge: String
)

And

This my TeamImplsTest

class TeamImplsTest {

    @Mock
    private lateinit var teamView: TeamView

    @Mock
    private lateinit var teamPresenter: TeamPresenter

    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)

        teamPresenter = TeamImpls(teamView)
    }

    @Test
    fun loadTeamDetail() {
        val teams = TeamModel(arrayListOf())

        val teamId = "133613"

        teamPresenter.loadTeamDetail(teamId)

        Mockito.verify(teamView).onSuccess(teams)
    }
}

i got error

Wanted but not invoked:
teamView.onSuccess(TeamModel(teams=[]));
-> at com.fathurradhy.matchschedule.domain.presenter.TeamImplsTest.loadTeamDetail(TeamImplsTest.kt:34)
Actually, there were zero interactions with this mock.

Wanted but not invoked:
teamView.onSuccess(TeamModel(teams=[]));
-> at com.fathurradhy.matchschedule.domain.presenter.TeamImplsTest.loadTeamDetail(TeamImplsTest.kt:34)
Actually, there were zero interactions with this mock.

Answer:

You're not mocking the API call as loadTeamDetail creates its own API instance.

To enable you to test the API call behaviour you could provide the API instance through your constructor, e.g.

class TeamImpls(private val api: API, private val teamView: TeamView) : TeamPresenter {

    override fun loadTeamDetail(team_id: String) {
        val call = api.getTeam(team_id)

This would then allow you to mock the api behaviour and verify the presenter calls the correct method when the call fails/succeeds, e.g.

class TeamImplsTest {

    @Mock
    private lateinit var teamView: TeamView

    @Mock
    private lateinit var api: API

    @Mock
    private lateinit var teamPresenter: TeamPresenter

    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)

        teamPresenter = TeamImpls(api, teamView)
    }

    @Test
    fun loadTeamDetail() {
        val teams = TeamModel(arrayListOf())

        val teamId = "133613"

        // Use retrofit-mock to create your mockResponse.
        // See: https://github.com/square/retrofit/tree/master/retrofit-mock
        Mockito.`when`(api.getTeam(teamId)).thenReturn(Calls.response(teams)

        teamPresenter.loadTeamDetail(teamId)

        Mockito.verify(teamView).onSuccess(teams)
    }
}

Question:

I'm trying to do some unit test on a basic Android app. it just do a login to some WS using retrofit my app has a MVP pattern.

What I'm doing?

call to presenter layer this will call to interactor and here I will call to my service

    @Override
    public void doLogin(String user, String pwd, final LoginListener loginListener) {

        try {
            final LoginRequest request = new LoginRequest();
            request.setEmpleado(user);
            request.setPwd(pwd);

            Callback<LoginResponse> callback = new Callback<LoginResponse>() {
                @Override
                public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
                    if(response != null && response.isSuccessful() && response.body() != null) {
                        if("00".equals(response.body().getCodigo())) {
                            loginListener.authOK();
                        } else {
                            loginListener.showError();
                        }
                    } else {
                        loginListener.showError();
                    }
                }

                @Override
                public void onFailure(Call<LoginResponse> call, Throwable t) {
"+t.getMessage()+" "+t.getCause());
                    if(t instanceof SocketTimeoutException) {
                        loginListener.showError();
                    } else {
                        loginListener.showError();
                    }
                }
            };

            WSLogin wsLogin = RetrofitClient.getInstance().getRetrofit().create(WSLogin.class);
            wsLogin.autenticar(request).enqueue(callback);

        } catch (Exception e) {
            loginListener.showError();
            e.printStackTrace();
        }

My service it's called but i never get into callback

Test

package com.arleckk.loginmvpci.login;


import com.arleckk.loginmvpci.login.presenter.LoginListener;
import com.arleckk.loginmvpci.login.presenter.LoginPresenter;
import com.arleckk.loginmvpci.login.presenter.LoginPresenterImpl;
import com.arleckk.loginmvpci.login.view.LoginView;
import com.arleckk.loginmvpci.model.LoginResponse;
import com.arleckk.loginmvpci.network.WSLogin;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.modules.junit4.PowerMockRunner;

import java.io.IOException;

import retrofit2.Call;
import retrofit2.Response;

import static org.junit.Assert.assertEquals;

@RunWith(PowerMockRunner.class)
@PowerMockIgnore("javax.net.ssl.*")
public class LoginTest {

    @Mock private LoginView loginView;
    @Mock private LoginPresenter loginPresenter;
    @Mock private LoginListener loginListener;
    @Mock private Call<LoginResponse> loginResponseCall;
    Response<LoginResponse> loginResponseResponse;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        loginPresenter = new LoginPresenterImpl(loginView);
    }

    @Test
    public void testOK() throws IOException {
        loginPresenter.doLogin("TEST", "TEST1234");
    }


}

Another question is: do am I really doing unit test? I mean unit test only test a "Unit" of the code.

I'm expecting a LoginResponse object and then compare it and if it is equals to "00" it's sucessful


Answer:

No, you're not. For a few reasons. First off, you don't have a test here. You don't have a single assertion. No matter what happens your code will say pass. So it isn't a test. A test would be to say call doLogin with a working login, and ensure that loginListener.authOK() is called. Then another test that uses a bad password, and checks that showError is called. Without that all you have is a waste of time.

Second- this is horribly scoped for a unit test. For a unit test, you should be checking that the smallest unit of code works. Here, you're checking that your entire networking stack, and your server, all work. That's way too much. And a unit test should never depend on an outside server working, that will just lead to a flaky test- something like that should be in an integration suite.

Your code right now isn't optimized for testing. If it was- you wouldn't be creating the retrofit client via a singleton in the code. You'd pass it into doLogin. That way you could pass in a mock in a test that could return a fake response, and then test whether your code can correctly identify the a fake success and failure response correctly, removing the server dependency yet testing all of the functionality.

Question:

I want to test a method of my class using Mockito.

public class SplashPresenter {
    public volatile State mField1 = State.DEFAULT;
    public volatile State mField2 = State.DEFAULT;

    boolean stateFlagsAreAllCompleted(@NonNull final ISplashView view) {
        if (mField1 == State.COMPLETE //
                && mField2 == State.COMPLETE) {

            // Check Forced Update
            final int updateCheckResult = checkForcedUpdate(); // <===
            if (updateCheckResult == MyConstants.PRODUCTION_UPDATE_AVAILABLE) {
                view.displayForcedUpdateAlert(false);
                return true;
            }

            if (updateCheckResult == MyConstants.BETA_UPDATE_AVAILABLE) {
                view.displayForcedUpdateAlert(true);
                return true;
            }

            view.restartLoader();
            // Move to the home screen
            return true;
        }

        return false;
    }

    int checkForcedUpdate() {
    ...... // my codes
    }
}

and this is my test class:

public class SplashPresenterTest_ForStateFlags {

    private Context mContext;
    private ISplashView mView;

    @Before
    public void setUp() throws Exception {
        mContext = Mockito.mock(Context.class);
        mView = Mockito.mock(ISplashView.class);
    }

    @Test
    public void stateFlagsAreAllCompleted() throws Exception {
        SplashPresenter presenter = Mockito.mock(SplashPresenter.class);
        presenter.mField1 = State.COMPLETE;
        presenter.mField2 = State.COMPLETE;

        when(presenter.checkForcedUpdate()).thenReturn(1);

        boolean actual = presenter.stateFlagsAreAllCompleted(mView);
        System.out.println("actual: " + actual + ", " +
                presenter.mField1 + ", " +
                presenter.checkForcedUpdate());
        assertTrue(actual);
    }
}

Test failure is what happens at the end. This is the output:

actual: false, COMPLETE, 1

The thing that I don't understand is even I change the stateFlagsAreAllCompleted method to following code then still test fails with above output.

boolean stateFlagsAreAllCompleted(@NonNull final ISplashView view) {

    return true;
}

Answer:

You've not yet mocked the behavior for the method stateFlagsAreAllComplete. You need to do:

when(presenter.stateFlagsAreAllComplete(Matchers.any()).thenReturn(true);

You can fine tune the Matchers.any() argument to the class type you want.

EDIT: I see that you are trying the test the method stateFlagsAreAllComplete. Since you are trying to test the method stateFlagsAreAllComplete of the class SplashPresenter, you cannot do so by mocking the class whose method is under test. You will have to work with an instance of the class. Mocked methods should only be used while testing when they are called in another method under test.

You will have to create an instance of the class you want to test.

Question:

I try to create test for my presenter, but when I run it, I got this kind of error

org.mockito.exceptions.misusing.WrongTypeOfReturnValue:
ScalarSynchronousObservable cannot be returned by getContext()
getContext() should return Context

I create my presenter test class like this

public class CreateTalkPresenterTest {

    @Mock
    TalkService talkService;

    @Mock
    CreateTalkMvpView createTalkMvpView;

    CreateTalkPresenter createTalkPresenter;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        talkService = ServiceFactory.createMapi(createTalkMvpView.getContext(), TalkService.class);
        createTalkPresenter = new CreateTalkPresenter(Schedulers.immediate(), Schedulers.immediate());
        createTalkPresenter.attachView(createTalkMvpView);
    }

    @Test
    public void createTalkSuccessfullTest() {
        TalkService.TalkResultModel talkResultModel = MockModel.newTalkResultModel();

        when(talkService.createNewTalk(
                FileUtil.createPartFromString("Lorem Ipsum dolor"),
                FileUtil.createPartFromString("100"),
                null,
                FileUtil.createPartFromString("0")
        )).thenReturn(Observable.just(talkResultModel));

        createTalkPresenter.callCreateTalk("Lorem Ipsum dolor", "100", null);

        verify(createTalkMvpView).showProgressIndeterminate();
        verify(createTalkMvpView).hideProgressIndeterminate();
        verify(createTalkMvpView).showTalkCreated(talkResultModel.object);
    }
}

and for Mock the result I use this class

public class MockModel {

    public static TalkService.TalkResultModel newTalkResultModel(){
        TalkService.TalkResultModel talkResultModel = new TalkService.TalkResultModel();
        talkResultModel.code = 600;
        talkResultModel.message = "Successfully executed!";
        talkResultModel.object = newTalkModel();

        return talkResultModel;
    }

    public static TalkModel newTalkModel(){
        Random random = new Random();
        String index = String.valueOf(random.nextInt(100));
        TalkModel talkModel = new TalkModel();
        talkModel.id = index;
        talkModel.content = "Lorem Ipsum dolor";
        talkModel.categorytalk = newCategoryTalkModel("Category "+index);
        talkModel.creator = newConsumerModel("User "+index);
        return talkModel;
    }

    public static CategoryTalkModel newCategoryTalkModel(String name){
        CategoryTalkModel categoryTalkModel = new CategoryTalkModel();
        categoryTalkModel.id = "100";
        categoryTalkModel.name = name;
        return categoryTalkModel;
    }

    public static ConsumerModel newConsumerModel(String name){
        Random random = new Random();
        String index = String.valueOf(random.nextInt(100));
        ConsumerModel consumerModel = new ConsumerModel();
        consumerModel.id = index;
        consumerModel.username = name;
        consumerModel.email = name+"@domain.com";
        consumerModel.fullName = "Fullname "+name;
        return consumerModel;
    }
}

And this is the presenter class that I want to test

public class CreateTalkPresenter implements Presenter<CreateTalkMvpView> {

    private CreateTalkMvpView createTalkMvpView;
    private TalkService mApiTalkService;
    private TalkService.TalkResultModel talkResultModel;
    private final Scheduler mainScheduler, ioScheduler;

    private Subscription subscription;

    public CreateTalkPresenter(Scheduler ioScheduler, Scheduler mainScheduler) {
        this.ioScheduler = ioScheduler;
        this.mainScheduler = mainScheduler;
    }

    @Override
    public void attachView(CreateTalkMvpView view) {
        createTalkMvpView = view;
    }

    @Override
    public void detachView() {
        createTalkMvpView = null;
        unsubscribe();
    }

    private void unsubscribe() {
        if (subscription != null) subscription.unsubscribe();
    }

    public void callCreateTalk(String content, String categoryId, String filePath) {
        mApiTalkService = ServiceFactory.createMapi(createTalkMvpView.getContext(), TalkService.class);

        unsubscribe();
        createTalkMvpView.showProgressIndeterminate();
        subscription = mApiTalkService.createNewTalk(
                FileUtil.createPartFromString(content),
                FileUtil.createPartFromString(categoryId),
                filePath != null ? FileUtil.prepareFilePart("picture", new File(filePath)) : null,
                FileUtil.createPartFromString("0"))
                .observeOn(mainScheduler)
                .subscribeOn(ioScheduler)
                .subscribe(new Subscriber<TalkService.TalkResultModel>() {
                    @Override
                    public void onCompleted() {
                        createTalkMvpView.hideProgressIndeterminate();
                        createTalkMvpView.showTalkCreated(talkResultModel.object);
                    }

                    @Override
                    public void onError(Throwable e) {
                        createTalkMvpView.hideProgressIndeterminate();
                        WarningUtil.onApiError(createTalkMvpView.getContext(), 0, e.getMessage());
                    }

                    @Override
                    public void onNext(TalkService.TalkResultModel talkResultModel) {
                        CreateTalkPresenter.this.talkResultModel = talkResultModel;
                    }
                });

    }
}

I'm using retrofit 2.1.0 and rx android in this case. So if someone have any idea, what I'm doing wrong in my code. Please help me

Thanks.


Answer:

talkService isn't a mock. Even though you have this set:

@Mock
TalkService talkService;

You then overwrite it in your @Before method setUp:

talkService = ServiceFactory.createMapi(createTalkMvpView.getContext(), TalkService.class);

So in your test, this happens to a real TalkService implementation:

when(talkService.createNewTalk(/* ... */
    )).thenReturn(Observable.just(talkResultModel));

Which then calls a real createNewTalk method, which starts with this:

mApiTalkService = ServiceFactory.createMapi(
    createTalkMvpView.getContext(), TalkService.class);

The rest of the method isn't important, because Mockito's when works by mocking the last method that was called before/within the call to when, and nothing else in that method interacts with mocks. If talkService were a mock, then when(talkService.createNewTalk(/*...*/)) would stub the method createNewTalk, but instead it stubs that last mock method call getContext. This makes it look like:

when(createTalkMvpView.getContext()).thenReturn(Observable.just(talkResultModel));

...which exactly matches your error message:

org.mockito.exceptions.misusing.WrongTypeOfReturnValue: ScalarSynchronousObservable cannot be returned by getContext()


To fix this, just remove your talkService assignment so the when method call is actually a mock, or use a real talkService as you've initialized it and remove the @Mock annotation and when and verify statements.

Question:

I want to create a test for presenter class using mockito tried few ways but getting error mention below. I am following these links here and here and my presenter class

public class SignInPresenterImpl extends BasePresenterImpl implements SignInPresenter {

    private SignInView mSignInView;
    private SignInInteractor mSignInInteractor;

    /**
     * Constructor
     *
     * @param signInView the associated SignIn view
     */
    public SignInPresenterImpl(@NonNull final SignInView signInView) {
        mSignInView = signInView;
        mSignInInteractor = new SignInInteractorImpl();

    }

    @Override
    public void onSignInClicked(final String email, final String password) {

        // checking for validation
        if (!ValidationUtil.checkEmail(email)) {
            mSignInView.showErrorMessage(R.string.error_invalid_email);
            return;
        }

        if (!ValidationUtil.checkPassword(password)) {
            mSignInView.showErrorMessage(R.string.error_invalid_password);
            return;
        }

        mSignInView.showLoading();
        mSignInInteractor.login(email, password, new BaseInteractor.ApiListener() {
            @Override
            public void onSuccess(final CommonResponse commonResponse) {
                //todo handle success
            }

            @Override
            public void onFailure(final ApiError apiError, final Throwable throwable) {

                if (isViewAttached()) {
                    mSignInView.hideLoading();
                    if (apiError != null) {
                        mSignInView.showErrorMessage(apiError.getMessage());
                    } else {
                        // resolve error through throwable
                        mSignInView.showErrorMessage(parseThrowableMessage(throwable));

                    }
                }
            }
        });
    }
}

and my presenter test class is

public class SignInPresenterImplTest {

    @Mock
    BaseInteractor.ApiListener listener;
    @Mock
    private SignInView mSignInView;
    @Mock
    private SignInInteractor mSignInInteractor;
    private SignInPresenter signInPresenter;

    @Before
    public void setUp() throws Exception {
        // Mockito has a very convenient way to inject mocks by using the @Mock annotation. To
        // inject the mocks in the test the initMocks method needs to be called.
        MockitoAnnotations.initMocks(this);

        //Get a refrence to the class test.
        signInPresenter = new SignInPresenterImpl(mSignInView);
    }

    @Test
    public void signInAndShowProgress() {
        signInPresenter.onSignInClicked("", "");

        mSignInView.showErrorMessage("");

        verify(mSignInView).showLoading("Loading");

    }
}

mSignInView shows below error

Wanted but not invoked: mSignInView.showLoading("Loading");

Please suggest me how to implement test cases in a correct way what I am doing wrong in it.

Thanks in advance


Answer:

In your method under test, the showLoading method is invoked with no attributes.. i think you should expect that and possibly verify that no error message has been shown:

@Test
public void signInAndShowProgress() {
    signInPresenter.onSignInClicked("", "");

    verify(mSignInView, times(0)).showErrorMessage(Mockito.any(String.class));

    verify(mSignInView).showLoading();

}