Reputation: 1175
I am trying to test a Spring Controller using Mockito. I have mocked the object also used when()
as per this question , but I am still facing the null pointer exception. Please suggest a way to solve this exception.
Github repository of this project
The particular line null pointer linked to is
modelMap.put("categories", simpleCategoryDAO.getAllCategories());
I have mocked simpleCategoryDAO and used when()
to return a list for getAllCategories()
.
Test Method:
@RunWith(MockitoJUnitRunner.class)
public class CategoryControllerTest {
private MockMvc mockMvc;
@InjectMocks
private CategoryController categoryController;
@Mock
private SimpleCategoryDAO simpleCategoryDAO;
@Before
public void setup() {
categoryController = new CategoryController();
mockMvc = MockMvcBuilders.standaloneSetup(categoryController).build();
}
@Test
public void categories_ShouldRenderCategoriesView() throws Exception {
List<Category> ALL_CATEGORIES = Arrays.asList(
new Category(1,"Funny"),
new Category(2,"JoyFul")
);
Mockito.when(simpleCategoryDAO.getAllCategories()).thenReturn(ALL_CATEGORIES);
mockMvc.perform(get("/categories"))
//.andExpect((MockMvcResultMatchers.model()).attribute("categories",ALL_CATEGORIES));
.andExpect(MockMvcResultMatchers.view().name("categories"));
}
}
Code of controller
@Controller
public class CategoryController {
@Autowired
SimpleCategoryDAO simpleCategoryDAO;
@Autowired
SimpleGifDAO simpleGifDAO;
@RequestMapping("/categories")
public String getAllCategories(ModelMap modelMap) {
modelMap.put("categories", simpleCategoryDAO.getAllCategories());
return "categories";
}
@RequestMapping("/category/{categoryID}")
public String getGifsByCategoryID(@PathVariable int categoryID,ModelMap modelMap){
modelMap.put("gifs", simpleGifDAO.findGifsByCategoryID(categoryID));
modelMap.put("category",simpleCategoryDAO.getCategoryByID(categoryID));
return "category";
}
}
Exception:
java.lang.NullPointerException: null
at com.teja.controller.CategoryController.getAllCategories(CategoryController.java:23) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_73]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_73]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_73]
at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_73]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221) ~[spring-web-4.1.7.RELEASE.jar:4.1.7.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137) ~[spring-web-4.1.7.RELEASE.jar:4.1.7.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110) ~[spring-webmvc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:776) ~[spring-webmvc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:705) ~[spring-webmvc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959) ~[spring-webmvc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893) ~[spring-webmvc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967) [spring-webmvc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:858) [spring-webmvc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:622) [tomcat-embed-core-8.0.23.jar:8.0.23]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843) [spring-webmvc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:65) [spring-test-4.1.7.RELEASE.jar:4.1.7.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) [tomcat-embed-core-8.0.23.jar:8.0.23]
at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:167) [spring-test-4.1.7.RELEASE.jar:4.1.7.RELEASE]
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134) [spring-test-4.1.7.RELEASE.jar:4.1.7.RELEASE]
at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:144) [spring-test-4.1.7.RELEASE.jar:4.1.7.RELEASE]
at CategoryControllerTest.categories_ShouldRenderCategoriesView(CategoryControllerTest.java:46) [classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_73]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_73]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_73]
at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_73]
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) [junit-4.12.jar:4.12]
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) [junit-4.12.jar:4.12]
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) [junit-4.12.jar:4.12]
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) [junit-4.12.jar:4.12]
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) [junit-4.12.jar:4.12]
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) [junit-4.12.jar:4.12]
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner.run(ParentRunner.java:363) [junit-4.12.jar:4.12]
at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37) [mockito-core-1.10.19.jar:na]
at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62) [mockito-core-1.10.19.jar:na]
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) [.cp/:na]
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) [.cp/:na]
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) [.cp/:na]
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) [.cp/:na]
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) [.cp/:na]
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) [.cp/:na]
Upvotes: 3
Views: 25378
Reputation: 125
I had some issues with the provided solution so I thought I'd share how I solved it. My issue was that when the controller called a method on the DAO it was throwing NullPointerException, because I didn't want to use setter injection to provide the mocked DAO to the controller (I refused to create a setter method in the DAO just to be able to test everything).
Basically for the OP it would require:
Like so:
@RunWith(MockitoJUnitRunner.class)
public class CategoryControllerTest {
private MockMvc mockMvc;
@Mock
private SimpleCategoryDAO simpleCategoryDAO;
@InjectMocks
private CategoryController categoryController;
@Before
public void setup() {
mockMvc = MockMvcBuilders.standaloneSetup(categoryController).build();
}
@Test
public void categories_ShouldRenderCategoriesView() throws Exception {
List<Category> ALL_CATEGORIES = Arrays.asList(
new Category(1,"Funny"),
new Category(2,"JoyFul")
);
Mockito.when(simpleCategoryDAO.getAllCategories()).thenReturn(ALL_CATEGORIES);
mockMvc.perform(get("/categories"))
//.andExpect((MockMvcResultMatchers.model()).attribute("categories",ALL_CATEGORIES));
.andExpect(MockMvcResultMatchers.view().name("categories"));
}
}
Upvotes: 1
Reputation: 9100
The problem is on your test class Before method you are instantiating new controller
@Before
public void setup() {
categoryController = new CategoryController();
mockMvc = MockMvcBuilders.standaloneSetup(categoryController).build();
}
Here is how I do test for Controller
Controller Class :
@Controller
public class CategoryController {
private SimpleCategoryDAO simpleCategoryDAO;
private SimpleGifDAO simpleGifDAO;
@Autowired
public void setSimpleGifDAO(SimpleGifDAO simpleGifDAO) {
this.simpleGifDAO = simpleGifDAO;
}
@Autowired
public void setSimpleCategoryDAO(SimpleCategoryDAO simpleCategoryDAO) {
this.simpleCategoryDAO = simpleCategoryDAO;
}
@RequestMapping("/categories")
public String getAllCategories(ModelMap modelMap) {
modelMap.put("categories", simpleCategoryDAO.getAllCategories());
return "categories";
}
@RequestMapping("/category/{categoryID}")
public String getGifsByCategoryID(@PathVariable int categoryID, ModelMap modelMap) {
modelMap.put("gifs", simpleGifDAO.findGifsByCategoryID(categoryID));
modelMap.put("category", simpleCategoryDAO.getCategoryByID(categoryID));
return "category";
}
}
Notice I'm using setter injection here not field injection. You can also use constructor injection ( preferred way for me).
In you test class
@RunWith(MockitoJUnitRunner.class)
public class CategoryControllerTest {
private MockMvc mockMvc;
@Mock
private SimpleCategoryDAO simpleCategoryDAO;
@Before
public void setup() {
final CategoryController categoryController = new CategoryController();
//notice here I'm setting the mocked dao here
// if you didn't use @RunWith(MockitoJUnitRunner.class)
// you can do: simpleCategoryDAO = Mockito.mock(SimpleCategoryDAO.class);
categoryController.setSimpleCategoryDAO(simpleCategoryDAO);
mockMvc = MockMvcBuilders.standaloneSetup(categoryController).build();
}
@Test
public void categories_ShouldRenderCategoriesView() throws Exception {
List<Category> ALL_CATEGORIES = Arrays.asList(
new Category(1, "Funny"),
new Category(2, "JoyFul")
);
Mockito.when(simpleCategoryDAO.getAllCategories()).thenReturn(ALL_CATEGORIES);
mockMvc.perform(get("/categories"))
//.andExpect((MockMvcResultMatchers.model()).attribute("categories",ALL_CATEGORIES));
.andExpect(MockMvcResultMatchers.view().name("categories"));
}
}
Take a look at Before method
on test. I'm setting the mocked DAO
on the new instance of controller that I've created and then I'm creating the MockMvc
using same instance of controller.
Upvotes: 10