使用spring-test-mvc对REST控制器进行单元测试

9
我已将Spring依赖升级到Spring 3.1.1.RELEASE,并尝试使用spring-test-mvc来对一个简单的Controller进行单元测试。我一直在遵循Spring REST Controller Test with spring-test-mvc framework中使用的技术,因为它似乎对那个人起作用了,但我迄今为止还没有成功。我认为我在测试上下文文件中缺少了一些关键配置。
我没有收到任何错误信息。我知道它不起作用的原因是因为Hello World从未被打印出来(请参见Controller)。我在这里漏掉了什么?
@Controller
@RequestMapping("/debug")
public class DebugOutputController {

    @RequestMapping(method = RequestMethod.POST)
    public void saveDebugOutput(@RequestBody DebugOutput debugOutput, HttpServletResponse response) {
        System.out.println("Hello World");
    }
}

测试类:

@RunWith(SpringJUnit4ClassRunner.class) //this lets tests access Spring beans defined in the context config file
@ContextConfiguration(locations={"file:src/test/resources/itest/restAPITestContext.xml"}) //tells the test where to get configuration and beans to be used by the test.
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class,  TransactionalTestExecutionListener.class}) //overrides the default stack of listeners
public class ITRestAPI{

@Autowired
private DebugOutputController debugOutputController;

private MockMvc mockMvc;

@Before
public void setUp() throws Exception {
    mockMvc = MockMvcBuilders.standaloneSetup(debugOutputController).build();
}

@After
public void tearDown() throws Exception {
}

@Test
public void shouldPerformPost() throws Exception {
    this.mockMvc.perform(post("/debug"));
}
}

restAPITestContext.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:mvc="http://www.springframework.org/schema/mvc"
   xmlns:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="
    http://www.springframework.org/schema/mvc 
    http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.1.xsd">

    <mvc:annotation-driven />
    <mvc:default-servlet-handler />
    <context:component-scan resource-pattern="*DebugOutputController*" base-package="com.company.project.servlet" />    

</beans>

spring-test-mvc非常有前途,但缺乏文档。除了目前的README之外,您还知道其他资料吗? - Mike Partridge
@MikePartridge 我找到的所有关于它的信息都来自他们的Github网站。 - CFL_Jeff
2个回答

20

原来出现了一个HttpMessageNotReadable异常,但我没看见,因为没有任何记录或输出。我通过在测试类中使用DefaultRequestBuilder类构建HTTP请求,并添加andDo(print())方法找到了它:

DefaultRequestBuilder requestBuilder = MockMvcRequestBuilders.post("/debug").contentType(MediaType.APPLICATION_JSON).body(new String("{\"T1\":109.1, \"T2\":99.3}").getBytes());
this.mockMvc.perform(requestBuilder).andDo(print());
所以在此之后,使用andDo(print())的输出,我可以看到抛出了HttpMessageNotReadable异常,但不知道异常的详细信息或是导致它的原因。为了查看详细信息,我必须将以下内容添加到控制器类中,将异常详细信息写入响应主体:
@ExceptionHandler(HttpMessageNotReadableException.class)
@ResponseBody
public String handleException1(HttpMessageNotReadableException ex)
{
    return ex.getMessage();
}

这显示了以下异常:

Could not read JSON: Unrecognized field "T1" (Class com.company.project.model.device.DebugOutput), not marked as ignorable
我在我的模型类的setter方法上添加了@JsonProperty注解来解决这个问题。
@JsonProperty("T1")
public void setT1(Float t1) {
    T1 = t1;
}

你提到的“print()”方法是什么?我在测试类中找不到它,而且由于你的测试类没有继承任何东西,你能指出你从哪里得到它或它的作用吗?谢谢。 - Mathias Conradt
2
@MathiasLin 我使用静态导入的方式来使用print()方法,就像这样:import static org.springframework.test.web.server.result.MockMvcResultHandlers.print; 这个方法会打印有关发送请求的详细信息。在调试时非常有用。 - CFL_Jeff
4
应该指出实际的导入语句如下:import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print - leojh

0

我刚刚花了很长时间来调试类似的问题,我的解决方案是执行以下操作:

MvcResult mvcResult = mockMvc
        .perform(
                post("/api/v1/admin/licences/{licenceId}/dataAccess", licenceId)
                        .header(POLLEN_INTERNAL, configuration.getPollenInternalSecret())
                        .header(USER_TYPE, USER_TYPE_OWNER)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(mapper.writeValueAsString(productHierarchyBeans)))
        .andReturn();

这个 mvcResult 变量将包含所有的错误或响应实体。然后您可以在调试器中分析它,或者使用类似 mvcResult.getResponse()mvcResult.getResolvedException() 的方法来找出是什么起作用或不起作用,然后修复问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接