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?
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);