0
votes

I am trying MVP pattern with TDD.

I have the following contract for Model, View And Presenter

Contract Class

interface GithubContract {
    interface View {
        void displayUsers(List<GurkhaComboDTO> userList);
    }

    interface Model {
        void getUsersAndPromptPresenter(String userName, Presenter presenter);

    }

    interface Presenter {

        void searchUsers(String userName);

        void loadUsers(List<GithubUserDTO> userList);
    }
}

I am trying to unit test the presenter logic like this :

Test Class

@RunWith(MockitoJUnitRunner.class)
public class GithubPresenterWithMockitoTest {

    @Mock
    GithubContract.Model mockedModel;

    @Test
    public void shouldDisplayUsersToScreen() {
        //given
        final GithubContract.View view = new MockView(); // I have created the mock myself for the view this time.
        final GithubContract.Presenter presenter = new GithubPresenter(view, mockedModel);
        ***********************************************************
        // I do not know what to write here 
        ****************************************************
        presenter.searchUsers("");
        Assert.assertEquals(true, ((MockView) (view)).enoughItems);
    }
}

My MockView / VIEW class looks like this :

This is -> Mock class

class MockView implements GithubContract.View {
        boolean enoughItems = false;

        @Override
        public void displayUsers(List<GurkhaComboDTO> userList) {
            enoughItems = true;
        }
}

My PRESENTER implementation of contract is like this ..

This is -> Real Class

    class GithubPresenter implements GithubContract.Presenter {

            private GithubContract.View view;
            private GithubContract.Model model;

        GithubPresenter(GithubContract.View view, GithubContract.Model model) {

                this.view = view;
                this.model = model;
            }

        @Override
        public void searchUsers(String userName) {
            model.getUsersAndPromptPresenter(userName, this);
        }

        @Override
        public void loadUsers(List<GithubUserDTO> data) {

            if (data != null) { 
                if (!data.isEmpty()) {
                    view.displayUsers(users);
                }     
   }


    }

I have the MODEL class Implementation like this :

This is -> Real Class

public class GithubModel implements Model {

    @Inject
    GithubAPIService apiService;
    private Call<GithubUserListDTO> userListCall;

    private Context context;

    GithubModel(Context context) {
        this.context = context;
        apiService = Util.getAPIService(); // I am using dagger, retrofit and okhttp3 with GSON to get Objects directly from network call 

    }

    @Override
    public void getUsersAndPromptPresenter(final String userName, final GithubContract.Presenter presenter) {
        userListCall = apiService.searchGitHubUsers(userName);
        if(Util.isInternetConnected(context)) {
            userListCall.enqueue(new Callback<GithubUserListDTO>() {
                @Override
                public void onResponse(Call<GithubUserListDTO> call, Response<GithubUserListDTO> response) {

                    try {
                        presenter.loadUsers(response.body().getList());
                    } catch (Exception ignored) {
                        Util.log(ignored.getMessage());

                    }

                }

                @Override
                public void onFailure(Call<GithubUserListDTO> call, Throwable t) {

                }
            });
        }else {
Util.log("No Internet");
        }
    }
}

Now the real problem part:

I was successfully able to test the presenter with the mock of GithubContract.Model myself, But I want to use Mockito to mock the Model but as my getUsersAndPromptPresenter() method is abstract, returns void, takes parameters and calls back to presenter from an Inner class inside the method.

How can I mock my Model? If I need to bring some change in architecture in order to be able to make it testable, then please suggest it.

1

1 Answers

2
votes

You shouldn't pass presenter to Model, Model and Presenter shouldn't be tightly coupled because it prevents model classes from being reusable. Instead provide succesfull and error callbacks(or a composite object that contains both these callbacks). And then you will be able to capture that callback with mockito and call the required one. Also it's very common today to use RxJava, it makes it easier to mock Model classes.
And here is a general good practice: you should avoid to use And/Or words in method names because it indicates that the method is doing more than one thing which is bad