Using Mockito ‘when’ in controller testing

I’m trying to test my controller method in Play framework 2.4.6. Inside my controller method, I have the following code:

User user = accountService.getUserByEmail(email);
if (user == null) {
  //Path A
}
//Path B

When running the test, user will be null. Hence I can’t test Path B. I tried returning a User using Mockito when, but it didn’t work either. Is there any other way of doing it?

Below is my test code:

    RequestBuilder request = new RequestBuilder()
            .method("POST")
            .bodyForm(ImmutableMap.of("email", "[email protected]"))
            .uri(controllers.routes.ResetPasswordController.postResetPassword().url());

    when(accountService.getUserByEmail(anyString())).thenReturn(new User());

    assertEquals(OK, route(request).status());

Answer

Thanks to @Andriy for pointing me in the right direction for Dependency Injection.
I managed to solved the issue with the following setup.

Test:

public class TestClass {
@Inject
Application application;

final AccountService accountServiceMock = mock(AccountService.class);

@Before
public void setup() {
    Module testModule = new AbstractModule() {
        @Override
        public void configure() {
            bind(AccountService.class).toInstance(accountServiceMock);
        }
    };

    GuiceApplicationBuilder builder = new GuiceApplicationLoader()
            .builder(new ApplicationLoader.Context(Environment.simple()))
            .overrides(testModule);
    Guice.createInjector(builder.applicationModule()).injectMembers(this);

    Helpers.start(application);
}

@Test
public void testMethod() throws Exception {
    RequestBuilder request = new RequestBuilder()
            .session("userId", "1")
            .uri(controllers.routes.AccountController.addAccount().url());

    running(application, () -> {
        when(accountServiceMock.addAccount().thenReturn(true);
        assertEquals(OK, route(request).status());
    });
}

Controller:

@Singleton
public class AccountController extends Controller {
  private AccountService accountService;

  @Inject
  public Controller(AccountService a) {
      accountService = a;
  }

  public Result addAccount() {
     boolean success = accountService.addAccount();
  }
}

Interface:

@ImplementedBy(AccountServiceImpl.class)
public interface AccountService {
   boolean addAccount();
}

Implementation:

public class AccountServiceImpl implements AccountService {
   @Override
   public boolean addAccount() {
   }
}

My knowledge is minimal on the concepts going on here, but roughly:

  • Controller is stateless just like HTML, hence you need runtime dependency injection to get Play to recognise the mock object.

Useful documentations: https://www.playframework.com/documentation/2.4.x/JavaTestingWithGuice https://www.playframework.com/documentation/2.4.x/JavaDependencyInjection

Leave a Reply

Your email address will not be published. Required fields are marked *