Spring Rest Controller测试中的NullPointer异常 - Java

时间:2016-08-20 16:51:08

标签: java spring unit-testing spring-mvc nullpointerexception

我在Spring-Boot 1.4中有以下Rest Controller和单元测试:

HealthChecker控制器:

@RestController
public class HealthCheckerController {

   @Autowired
   private InstanceRepository instanceRepository;

   @RequestMapping(value = "/healthchecker", method = RequestMethod.GET)
   @ResponseBody
   public List<Instance> findAll() {
       return this.instanceRepository.findAll();
   }

HealthCheckerControllerTest:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@WebAppConfiguration
public class HealthCheckerControllerTest {

    private MockMvc mvc;

    @Autowired
    private InstanceRepository instanceRepository;

    @Before
    public void setUp() throws Exception {
        mvc = MockMvcBuilders.standaloneSetup(new HealthCheckerController()).build();

        this.instanceRepository.deleteAll();
        Instance first = new Instance("10.20.30.40", "ami-xxxxxxxx");
        Instance second = new Instance("10.20.30.41", "ami-xxxxxxxx");
        this.instanceRepository.save(first);
        this.instanceRepository.save(second);

        for (Instance instance : this.instanceRepository.findAll()) {
            System.out.println(instance);
        }
    }

    @Test
    public void testHealthChecker() throws Exception {
        mvc.perform(get("/healthchecker")).andExpect(status().isOk())
                .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)).andExpect(jsonPath("$", hasSize(2)))
                .andExpect(jsonPath("$[0].ipaddress", is("10.20.30.40")))
                .andExpect(jsonPath("$[0].ami", is("ami-xxxxxxxx")))
                .andExpect(jsonPath("$[1].ipaddress", is("10.20.30.41")))
                .andExpect(jsonPath("$[1].ami", is("ami-xxxxxxxx")));
    }
}

但是,当我执行单元测试时,它会给我以下错误:

Tests run: 21, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 19.83 sec <<< FAILURE! - in TestSuite
testHealthChecker on testHealthChecker(cloudos.HealthCheckerControllerTest)(cloudos.HealthCheckerControllerTest)  Time elapsed: 0.193 sec  <<< FAILURE!
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.NullPointerException
    at cloudos.HealthCheckerController.findAll(HealthCheckerController.java:39)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:114)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
    at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:65)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:167)
    at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
    at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:155)
    at cloudos.HealthCheckerControllerTest.testHealthChecker(HealthCheckerControllerTest.java:48)

从UI访问它可以正常工作:

[{"ipaddress":"10.20.30.40","ami":"ami-xxxxxxxx"},{"ipaddress":"10.20.30.41","ami":"ami-xxxxxxxx"}]

我理解问题是private InstanceRepository instanceRepositoryunit test没有被初始化,所以当它在HealthCheckerController内被访问时,它是空的,但是& #39;不是@Autowired的目的吗? 我怎么能解决这个问题?

1 个答案:

答案 0 :(得分:3)

当您使用MockMvcBuilders.standaloneSetup时,您需要手动设置您的控制器对象(而不是单元测试)

如果您想使用完整的Spring上下文(所有@Autowired个字段都可用),您需要使用MockMvcBuilders.webAppContextSetup

这应该有效:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@WebAppConfiguration
public class HealthCheckerControllerTest {

    private MockMvc mvc;

    @Autowired
    private WebApplicationContext webApplicationContext;

    @Autowired
    private InstanceRepository instanceRepository;

    @Before
    public void setUp() throws Exception {

        mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();

        this.instanceRepository.deleteAll();
        Instance first = new Instance("10.20.30.40", "ami-xxxxxxxx");
        Instance second = new Instance("10.20.30.41", "ami-xxxxxxxx");
        this.instanceRepository.save(first);
        this.instanceRepository.save(second);

        for (Instance instance : this.instanceRepository.findAll()) {
            System.out.println(instance);
        }
    }

    @Test
    public void testHealthChecker() throws Exception {
        mvc.perform(get("/healthchecker")).andExpect(status().isOk())
                .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)).andExpect(jsonPath("$", hasSize(2)))
                .andExpect(jsonPath("$[0].ipaddress", is("10.20.30.40")))
                .andExpect(jsonPath("$[0].ami", is("ami-xxxxxxxx")))
                .andExpect(jsonPath("$[1].ipaddress", is("10.20.30.41")))
                .andExpect(jsonPath("$[1].ami", is("ami-xxxxxxxx")));
    }
}

您最终可以尝试将构造函数添加到控制器并手动将现有存储库注入新创建的控制器:

@RestController
public class HealthCheckerController {

    @Autowired
    private InstanceRepository instanceRepository;

    public HealthCheckerController(InstanceRepository instanceRepository) {
        this.instanceRepository = instanceRepository;
    }

    @RequestMapping(value = "/healthchecker", method = RequestMethod.GET)
    @ResponseBody
    public List<Instance> findAll() {
        return this.instanceRepository.findAll();
    }
}

并且您的mvc配置应如下所示:

mvc = MockMvcBuilders.standaloneSetup(new HealthCheckerController(instanceRepository)).build();