Question

I am new to mockito and i want to make a unit test for user validation. Please find below the method i want to perform the unit test:

@RequestMapping(method = RequestMethod.POST, value = "/login")
public ModelAndView validateViewLogin(@ModelAttribute Person person,
        BindingResult result, HttpServletRequest request) {
    ModelAndView mav = new ModelAndView();

    String userName = person.getFirstName();
    String password = person.getPassword();
    boolean isUserValid = false;
    if (userName != null && password != null) {

        isUserValid = userManagerService.validateUserLogin(userName,
                password);

    }
    if (!isUserValid) {

         mav.setViewName("home");
         return mav;
    }
    mav.addObject("isUserValid", isUserValid);
    mav.setViewName("login");
    return mav;
}

As you can see above isUserValid method returns a boolean and my method i want to test returns a ModelAndView.

Please see my unit test below:

 `@Test public void testValidateOk() {


     MockHttpServletRequest request = new MockHttpServletRequest();
     MockHttpServletResponse response = new MockHttpServletResponse();
     Person person = new Person();
     ModelAndView mav = new ModelAndView();
     mav.setViewName("login");

     person.setFirstName("John");
     person.setPassword("123");





    LogInController controller = new LogInController();

    UserManagerServiceImpl mockpdao = mock(UserManagerServiceImpl.class);

    ReflectionTestUtils.setField(controller, "userManagerService", mockpdao);

    // given
     given(controller.validateViewLogin(person, result, request)).willReturn(mav);

    // when
     ModelAndView validateViewLogin=
             controller.validateViewLogin(person, result, request);
    // then
            assertEquals("home", validateViewLogin.getViewName());


}`

when i run my unit test i get the following error:

org.mockito.exceptions.misusing.WrongTypeOfReturnValue: ModelAndView cannot be returned by validateUserLogin() validateUserLogin() should return boolean


If you're unsure why you're getting above error read on. Due to the nature of the syntax above problem might occur because: 1. This exception might occur in wrongly written multi-threaded tests. Please refer to Mockito FAQ on limitations of concurrency testing. 2. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies - - with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.

at com.gemstone.presentation.LogInControllerTest.testValidateOk(LogInControllerTest.java:49)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

Any ideas how i can resolve this issue please?

Was it helpful?

Solution

I'm not familiar with BDD style Mockito, but I'm guessing that the line

given(controller.validateViewLogin(person, result, request)).willReturn(mav);

means that you are asking the controller to return the given model and view whenever the validateViewLogin method is called with the specified person, result and request. However the controller is not a mock, so this may be what is causing your error. What you should be doing instead is specifying the behaviour of how your mock user manager service should behave.

I notice that you are creating a mock of the UserManagerServiceImpl class. Given that it ends with 'Impl' I am guessing that there is a correspondng UserManagerService interface that you could mock instead. Mocktio can mock concrete classes, but it can not do this as easily as mocking an interface. Therefore if there is indeed an interface then I would mock that instead just to be safe.

You are injecting your mock using ReflectionTestUtils. This probably isn't the cause of your error, but if it is possible for you to do so then I'd recommend adding a public setter to your controller to inject it more safely and easily.

Taking the above points, I would write your test like the following:

@Test public void validateViewLogin_validLogin_returnsHomePage() {
    MockHttpServletRequest request = new MockHttpServletRequest();
    MockHttpServletResponse response = new MockHttpServletResponse();

    Person person = new Person();
    person.setFirstName("John");
    person.setPassword("123");

    LogInController controller = new LogInController();
    UserManagerService mockUserService = mock(UserManagerService.class);

    // Configure mock user service to accept the person
    when(mockUserService.validateUserLogin("John", "123")).thenReturn(true);

    // Inject mock user service into controller
    controller.setUserManagerService(mockUserService);

    // Attempt the validation
    ModelAndView mav =
        controller.validateViewLogin(person, result, request);

    // Check the result
    assertEquals("home", mav.getViewName());
}

Since I'm not familiar with the BDD syntax I have configured the mock using the line

when(mockUserService.validateUserLogin("John", "123")).thenReturn(true);

but I assume that this is equivalent to

given(mockUserService.validateUserLogin("John", "123")).willReturn(true);

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top