i have a spring mvc application and using mockito for my unit test.I keep getting null pointer exception when i run my unit test. :(
Please find below the method that my unit test will be based on:
@Controller
public class LogInController {
@Autowired
private MessageSource messageSource;
@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.addObject("failLog",messageSource.getMessage("login.user.fail", new String[] {" ", "" }, request.getLocale()));
mav.addObject("isUserValid", false);
mav.setViewName("login");
return mav;
}
mav.addObject("isUserValid", isUserValid);
mav.setViewName("home");
return mav;
}
Please find below my unit test:
@Test
public void validateViewLogin_NotValidLogin_returnsLoginPage() {
MockHttpServletRequest request = new MockHttpServletRequest();
Person person = new Person();
person.setFirstName("John");
person.setPassword("123");
isUserValid = false;
LogInController controller = new LogInController();
// Inject mock user service into controller
UserManagerService mockUserService = mock(UserManagerService.class);
controller.setUserManagerService(mockUserService);
// Configure mock user service to accept the person
when(mockUserService.validateUserLogin("John", "123")).thenReturn(
isUserValid);
// Attempt the validation
ModelAndView mav = controller
.validateViewLogin(person, result, request);
// Check the result
assertEquals("login", mav.getViewName());
}
Please find below stack trace error message when i run the unit test above:
java.lang.NullPointerException
at com.gemstone.presentation.LogInController.validateViewLogin(LogInController.java:99)
at com.gemstone.presentation.LogInControllerTest.validateViewLogin_NotValidLogin_returnsLoginPage(LogInControllerTest.java:79)
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)
Basically line 99 which is shown below is returning null according to the stack trace:
mav.addObject(
"failLog",
messageSource.getMessage("login.user.fail", new String[] {
" ", "" }, request.getLocale()));
Any ideas why i am getting the null pointer on this line please?However when i run my application it works fine and failLog message is displayed on my page.
thanks in advance.
My guess is that your messageSource is null. You are mocking your request, but not your messageSource, and where you are newing the login controller it's not being injected by Spring.
While running it would get injected by Spring automatically.
Edit to clarify:
First you need to be able to set it some how for testing. You can either add a setter or a constructor to get to it, such as:
@Controller
public class LogInController {
@Autowired
private MessageSource messageSource;
public void setMessageSource(MessageSource ms){
this.messageSource = ms;
}
// ......
}
Then your test would need to change as well:
@Test
public void validateViewLogin_NotValidLogin_returnsLoginPage() {
MockHttpServletRequest request = new MockHttpServletRequest();
Person person = new Person();
person.setFirstName("John");
person.setPassword("123");
isUserValid = false;
LogInController controller = new LogInController();
// Inject mock user service into controller
UserManagerService mockUserService = mock(UserManagerService.class);
/** ADDED **/
MessageSource ms = mock(MessageSource.class);
controller.setUserManagerService(mockUserService);
/** ADDED **/
controller.setMessageSource(ms);
// Configure mock user service to accept the person
when(mockUserService.validateUserLogin("John", "123")).thenReturn(
isUserValid);
/** ADDED **/
when(ms.getMessage("login.user.fail", new String[] {" ", "" }).thenReturn("message");
// Attempt the validation
ModelAndView mav = controller
.validateViewLogin(person, result, request);
// Check the result
assertEquals("login", mav.getViewName());
}
Just free handing this, so make sure I don't have any typos! Essentially you try the MessageSource as you did your UserManagerService, it's just an interface after all and can be mocked exactly the same way.