2

I am trying to test a LoginPresenter, and I am using Mockito for the mocks. Mockito doesnt let me verify a method invocation on the SUT so I have to mock its dependencies and verify their methods have been called by the LoginPresenter.

I got to the following situation:

LoginPresenter has a method called attemptLogin:

private void attemptLogin(String username, String password) {
    new LoginNetworkOperation(username, password).execute();
}

I have to mock LoginNetworkOperation and using Mockito, verify the method invocation on execute().

@Test
public void testWhenUserNameAndPasswordAreEnteredShouldAttemptLogin() throws Exception {
    LoginView loginView = Mockito.mock(LoginView.class);
    LoginNetworkOperation loginNetworkOperation = Mockito.mock(LoginNetworkOperation.class);
    Mockito.when(loginView.getUserName()).thenReturn("George");
    Mockito.when(loginView.getPassword()).thenReturn("aaaaaa");
    loginPresenter.setLoginView(loginView);
    loginPresenter.onLoginClicked();
    Mockito.verify(loginNetworkOperation.execute());
}

However, how do I make LoginPresenter use the mocked LoginNetworkOperation instead of the one it creates in the attemptLogin method? I need to change the design of LoginPresenter to use a member variable, and provide a setter for it, which is suboptimal because a local variable in the method is plenty, as it is used only there.

Am I going about this whole thing wrong?

Initially, I wanted to verify that LoginPresenter's attemptLogin is called, but Mockito can only verify mocked objects' methods and I cannot spy on LoginPresenter because it is final (generated by AndroidAnnotations)

Kaloyan Roussev
  • 14,515
  • 21
  • 98
  • 180
  • You might have a look at this answer: http://stackoverflow.com/questions/10585490/androidannotations-and-unit-testing#10621419 – aro_tech Mar 22 '16 at 10:11

1 Answers1

1

I found the answer in this video: https://www.youtube.com/watch?v=wEhu57pih5w

The biggest takeaway is: don't mix object creation logic with business logic which means don't instantiate objects in methods or constructors (probably use DI instead), because the test code has no power over what chain-reaction starts whenever a SUT's constructor or a method is called, that is bound to a new keyword.

That means that in my case, the LoginPresenter shouldn't be responsible for creating the LoginNetworkOperation object but should take it from the outside

That way I will be able to tell it to use the mock instead of the concrete implementation, and thus, I will be able to do my tests

Kaloyan Roussev
  • 14,515
  • 21
  • 98
  • 180