I was under the assumption that writing unit tests would be a lot easier when using the Model-View-Presenter (MVP) pattern but I'm not sure how to go forward with even beginning. I've added dependencies to start writing unit tests with Roboelectric and Mockito to mock all the dependencies being used in my presenter.
For some reference, here is an example of my presenter for login:
public class LoginPresenterImpl implements ILoginPresenter {
@Inject
Bus bus;
@Inject
ISharedPreferencesRepository mSharedPreferencesRepository;
private final String LOG_TAG = "LOGIN_PRESENTER";
private ILoginView loginView;
private LoginInteractorImpl loginInteractor;
private long mLastClickTime = 0;
public LoginPresenterImpl() {
MyApplication.getObjectGraph().inject(this);
this.loginInteractor = new LoginInteractorImpl();
}
@Override
public void setLoginView(ILoginView loginView) {
this.loginView = loginView;
if(mSharedPreferencesRepository.isLoggedIn()) {
Log.i(LOG_TAG, "User logged in already");
this.loginView.navigateToHome();
}
}
@Override
public void validateCredentials(String username, String password) {
if(SystemClock.elapsedRealtime() - mLastClickTime < 1000)
return;
mLastClickTime = SystemClock.elapsedRealtime();
if(username.equals("") || username == null) {
loginView.setUsernameError();
return;
} else if(password.equals("") || password == null){
loginView.setPasswordError();
return;
}
loginView.showProgress();
loginInteractor.login(username, password, this);
}
@Override
public void onUsernameError() {
loginView.setUsernameError();
loginView.hideProgress();
}
@Override
public void onPasswordError() {
loginView.setPasswordError();
loginView.hideProgress();
}
@Subscribe
@Override
public void onSuccess(LoginEvent event) {
if (event.getIsSuccess()) {
mSharedPreferencesRepository.setLogin(true);
mSharedPreferencesRepository.setFirstTime(true);
mSharedPreferencesRepository.setUserId(event.getUserId());
loginView.navigateToHome();
loginView.hideProgress();
}
}
Now onto my unit test (attempt):
First, correct me if I'm wrong, but in order to begin writing my test cases, I'll need to Mock a few objects:
Bus, ISharedPreferencesRepository, ILoginView, LoginInteractorImpl.
I ended up with something like this:
@RunWith(MockitoJUnitRunner.class)
public class LoginPresenterImplTest {
@Mock
private ILoginView view;
@Mock
private LoginInteractorImpl interactor;
@Mock
private LoginPresenterImpl presenter;
@Before
public void setUp(){
}
@Test
public void shouldShowErrorMessageWhenUsernameIsEmpty() throws Exception {
when(view.getUsername()).thenReturn("");
when(view.getPassword()).thenReturn("test");
presenter.validateCredentials(view.getUsername(), view.getPassword());
}
}
I'm a bit lost at the next steps to take. I'm trying to verify that the method loiginView.setOnUsernameError() will be called in this scenario by adding verify(view, times(1)).setUsernameError(); but this fails my test.