簡體   English   中英

junit:使用 mockmvc 測試控制器時注入的 bean 上的 NullPointer

[英]junit: NullPointer on injected bean when testing controller with mockmvc

所以我有這個測試用例:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:rest-context-test.xml")
public class CustomerControllerTest {

private MockMvc mockMvc;

@Before
public void setup() {
    this.mockMvc = MockMvcBuilders
            .standaloneSetup(new CustomerController()).build();
}


@Test
public void testGetCustomerById() throws Exception {
    mockMvc.perform(get("/customers/{ccid}", 1)).andExpect(status().isOk())
            .andExpect(content().contentType("application/json"))
            .andExpect(jsonPath("$.ccid").value("1"));
}

}

加載 rest-context-test.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd">

<bean id="customerServiceImpl"
    class="myorg.service.impl.MockCustomerServiceImpl" />

</beans>

希望能夠將 AutoWire customerServiceImpl 添加到我的控制器中:

@Controller
@RequestMapping("customers")
public class CustomerController {

private static Logger Logger = LoggerFactory
        .getLogger(CustomerController.class);

@Autowired
@Qualifier("customerServiceImpl")
private CustomerService customerService;


@RequestMapping(value = "/{ccid}", method = RequestMethod.GET, produces = "application/json")
@ResponseStatus(HttpStatus.OK)
@ResponseBody
public Customer getCustomerById(@PathVariable Integer ccid)
        throws BadRequestException, ServerErrorException,
        ResourceNotFoundException {
    Customer c = null;

    try {
        c = customerService.getCustomer(ccid);
    } catch (IllegalArgumentException iae) {
        // HTTP 400
        Logger.error("Invalid arguments submitted", iae);
        throw new BadRequestException();
    } catch (CsspException ce) {
        // HTTP 500
        Logger.error("Server error", ce);
        throw new ServerErrorException();
    }

    if (c == null) {
        // HTTP 404
        throw new ResourceNotFoundException();
    }

    return c;
}
}

但我的單元測試拋出以下跟蹤:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.NullPointerException
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:965)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:844)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:689)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:829)
at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:66)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:168)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:136)
at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:141)
at myorg.rest.controller.CustomerControllerTest.testGetCustomerById(CustomerControllerTest.java:41)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)
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)
Caused by: java.lang.NullPointerException
at myorg.rest.controller.CustomerController.getCustomerById(CustomerController.java:134)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle    (ServletInvocableHandlerMethod.java:104)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod    (RequestMappingHandlerAdapter.java:745)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal    (RequestMappingHandlerAdapter.java:686)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:953)
... 38 more

當 Controller 嘗試訪問 customerService 時會拋出此空指針:

@Autowired
@Qualifier("customerServiceImpl")
private CustomerService customerService;

為什么我的 MockCustomerServiceImpl 沒有自動連接到控制器中?

注意:包名已更改以保護無辜者

Spring 文檔

“webAppContextSetup”加載實際的 Spring MVC 配置,從而產生更完整的集成測試。 由於 TestContext 框架緩存加載的 Spring 配置,因此即使添加了更多測試,它也有助於保持測試快速運行。 此外,您可以通過 Spring 配置將模擬服務注入控制器,以便專注於測試 web 層。

另一方面,“standaloneSetup”更接近於單元測試。 它一次測試一個控制器,控制器可以手動注入模擬依賴項,並且不涉及加載 Spring 配置。 這樣的測試在風格上更集中,並且更容易查看正在測試的控制器,是否需要任何特定的 Spring MVC 配置,等等。 “standaloneSetup”也是編寫臨時測試以驗證某些行為或調試問題的一種非常方便的方法。

由此我明白,如果我需要一個 .xml 作為要加載的 Spring 配置文件,那么我需要使用“webAppContextSetup”。 如果我只需要對我的 Controller 進行非常簡單的測試,而不需要 Spring 配置,那么我會使用“standaloneSetup”方法。 就您而言,我認為您需要“webAppContextSetup”。

您忘記創建模擬對象,然后像這樣將它們注入控制器

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:rest-context-test.xml")
public class CustomerControllerTest 
{
    @Mock
    private CustomerService customerService;
    @InjectMocks
    private CustomerController customerController;

    private MockMvc mockMvc;

    @Before
    public void setup() 
    {
        MockitoAnnotations.initMocks(this);
        this.mockMvc = MockMvcBuilders
                .standaloneSetup(customerController).build();
    }


    @Test
    public void testGetCustomerById() throws Exception 
    {
        mockMvc.perform(get("/customers/{ccid}", 1)).andExpect(status().isOk())
                .andExpect(content().contentType("application/json"))
                .andExpect(jsonPath("$.ccid").value("1"));
    }
}

它通過添加注釋@RunWith(SpringRunner.class)@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)@AutoConfigureMockMvc幫助我修復了 NullPointerException

這是對我有用的代碼-

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class MyTestClass {
    @Autowired
    private MockMvc mockMvc;

    @Test
    public void myClassController() throws Exception {

        Object obj = new Object(); 

        obj.setA(1);
        obj.setB(2);
        obj.setC(3);

        ObjectMapper mapper = new ObjectMapper();

        String jsonString = mapper.writeValueAsString(obj); // this is the json body
 
        mockMvc.perform(post("/ENDPOINT")
                .contentType(MediaType.APPLICATION_JSON)
                .content(jsonString))
                .andDo(print())
                .andExpect(status().isOk());
              
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM