[英]Spring Controller Testing using Mockito , Null Pointer Exception
I am trying to test a Spring Controller using Mockito. 我正在尝试使用Mockito测试Spring Controller。 I have mocked the object also used when()
as per this question , but I am still facing the null pointer exception. 我已经按照这个问题嘲笑了还使用when()
的对象,但是我仍然面临着空指针异常。 Please suggest a way to solve this exception. 请提出解决此异常的方法。
Github repository of this project 该项目的Github存储库
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()
. 我模拟了simpleCategoryDAO并使用when()
返回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]
The problem is on your test class Before method you are instantiating new controller
问题出在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
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. 注意,我在这里使用的是setter注入,而不是现场注入。 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. 看一下测试Before method
。 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. 我在创建的新 控制器 实例上设置了mocked DAO
,然后使用相同的控制器实例创建MockMvc
。
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). 我的问题是,当控制器在DAO上调用方法时,它抛出NullPointerException,因为我不想使用setter注入将模拟的DAO提供给控制器(我拒绝在DAO中创建setter方法只是为了能够测试一切)。
Basically for the OP it would require: 基本上,对于OP它将需要:
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"));
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.