Spring REST控制器的单元测试'位置'标题

问题描述:

在Spring REST控制器中创建资源后,我将返回它在标题中的位置,如下所示。Spring REST控制器的单元测试'位置'标题

@RequestMapping(..., method = RequestMethod.POST) 
public ResponseEntity<Void> createResource(..., UriComponentsBuilder ucb) { 

    ... 

    URI locationUri = ucb.path("/the/resources/") 
     .path(someId) 
     .build() 
     .toUri(); 

    return ResponseEntity.created(locationUri).build(); 
} 

在单元测试中,我正在检查它的位置,如下所示。

@Test 
public void testCreateResource(...) { 
    ... 
    MockHttpServletRequestBuilder request = post("...") 
     .content(...) 
     .contentType(MediaType.APPLICATION_JSON) 
     .accept(MediaType.APPLICATION_JSON); 

    request.session(sessionMocked); 

    mvc.perform(request) 
     .andExpect(status().isCreated()) 
     .andExpect(header().string("Location", "/the/resources" + id); 
} 

此结果案例失败并显示以下消息。

java.lang.AssertionError: Response header Location expected:</the/resources/123456> but was:<http://localhost/the/resources/123456> 

好像我必须为期望的位置标题提供上下文前缀http://localhost

  • 硬编码上下文安全吗?如果是这样,为什么?
  • 如果不是,那么正确地为测试用例生成正确的方法是什么?

如果您不需要在响应的Location标头中有一个完整的URI(即没有要求,设计约束等):考虑切换到使用相对URI(从HTTP标准角度来看这是有效的 - 请参阅[1]:https://tools.ietf.org/html/rfc7231)相对URI是现代浏览器和库支持的建议标准。这将允许您测试端点的行为,并使其从长远来看不那么脆弱。

如果您需要断言的完整路径,因为你正在使用MockMvc,你可以在测试请求设置URI到你想要什么:

@Autowired 
private WebApplicationContext webApplicationContext; 

@Test 
public void testCreateResource() { 
    MockMvc mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); 
    mvc.perform(MockMvcRequestBuilders.get(new URI("http://testserver/the/resources"))); 

这将使注入建设者产生“http://testserver “当构建被调用时。请注意,未来的框架更改可能会导致您头痛,如果他们删除此测试行为。

我在猜测,因为您使用UriComponentsBuilder来建立您的URI它设置您的位置标题中的主机名。如果你使用的只是new URI("/the/resources")之类的东西,你的测试已经过去了。

在你的情况,我会使用redirectedUrlPattern匹配重定向URL:

.andExpect(redirectedUrlPattern("http://*/the/resources"))

这将匹配任何主机名,所以你不必硬编码本地主机。详细了解您可以与AntPathMatcherhere一起使用的不同模式。

+0

您的解决方案测试重定向行为。 OP想要测试位置标头。 我必须承认,直到今天我都不知道“redirectedUrlPattern” –