我将 Post-Redirect-Get 控制器与 Spring 的
RedirectView
、RedirectAttributes
和 addFlashAttributes
一起使用。使用浏览器手动进行重定向。但是,我无法使用 TestRestTemplate
测试此重定向到重定向控制器。即使我在其中设置了 TestRestTemplate
,HttpClientOption.ENABLE_REDIRECTS
也不会执行重定向(启用它实际上没有效果)。虽然 testRestTemplate.postForEntity(...)
返回 302 FOUND
重定向状态和位置,但我没有从 @PostMapping
控制器获取 flashAttributes,因此我无法在第二次调用中重用它们来模拟到 @GetMapping
控制器的重定向。
我知道这些flashAttributes可以使用
MockMVC
获得。但是,我正在尝试从测试数据库一直到表单和视图进行集成测试。
HttpClientOption.ENABLE_REDIRECTS
,
请告诉我我做错了什么。postForEntity
中的 Http 请求),
请描述一下。PRG控制器的适用部分如下:
@GetMapping(value={"/view"})
public String getMyentityView(HttpServletRequest request, Model model)
{
Myentity myentity = null;
//use RequestContextUtils.getInputFlashMap(request) to get custom "success" flashAttributes and add to model
//Do view processing
model.addAttribute("myentity", myentity);
return "eMyentityView";
}
//@GetMapping controller to get the form "/form" not incl for brevity
@PostMapping(value = {"/submit"})
public RedirectView myentitySubmit(@ModelAttribute("myentity") Myentity myentity, BindingResult bindingResult, RedirectAttributes redirAttrs) {
validator.validate(myentity, bindingResult);
if (bindingResult.hasErrors()) {
redirAttrs.addFlashAttribute(BindingResult.MODEL_KEY_PREFIX+"myentity", bindingResult);
redirAttrs.addFlashAttribute("myentity", myentity);
return new RedirectView("/form", true);
}
...
//Handle good new myentity, save, add custom "success" messages to flashAttributes, etc.
...
return new RedirectView("/view", true);
}
这是测试:
@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT, useMainMethod = UseMainMethod.ALWAYS)
//Other annotations
public class ElectionCrudIntegrationTests {
....
@Test
@Order(0020)
void givenTestMyentityWhenSubmitThenExpectedViewDataReturned() throws Exception {
//Get test entity from test data
Myentity tempMyentity = testData.getGoodTestData().get("test-myentity-001");
//Create test client
RestTemplateBuilder rtb = new RestTemplateBuilder().rootUri("http://localhost:7777");
TestRestTemplate trt = new TestRestTemplate(rtb, null, null, TestRestTemplate.HttpClientOption.ENABLE_REDIRECTS);
//No redirect occurs with this call - request returns after completing myentitySubmit method
//HttpRequester.makeMyEntityHttpRequest(tempMyentity) adds myentity props to request map
//(is there is a way to allow redirects in postForEntity's HttpRequest???)
ResponseEntity<String> responseSubmit = this.trt.postForEntity("/submit",
HttpRequester.makeMyEntityHttpRequest(tempMyentity), String.class);
//These asserts pass
assertEquals(HttpStatus.FOUND, responseSubmit.getStatusCode());
assertEquals("http://localhost:7777/view",
responseSubmit.getHeaders().get("Location").get(0).split(";")[0]);
//But I get null body and no flashAttributes in the headers
}
...
}
看起来 Spring 处理重定向的策略是执行两次调用,无论您使用 TestRestTemplate 还是 MockMvc。请参阅github问题。 鉴于此,MockMvc 似乎提供了最多的功能来完成所有需要完成的工作,包括从 Post 调用中获取 flashAttributes 和链接,测试它们,然后将其重新提交回 Get 调用。这可以通过以下方式完成:
@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT, useMainMethod = UseMainMethod.ALWAYS)
@AutoConfigureMockMvc
//Other annotations
public class ElectionCrudIntegrationTests {
....
@Test
@Order(0020)
void givenTestMyentityWhenSubmitThenExpectedViewDataReturned() throws Exception {
//Get test entity from test data
Myentity tempMyentity = testData.getGoodTestData().get("test-myentity-001");
//Add form properties (or whole entity) using MockMvc .param tools
MvcResult mv = mvc.perform(post("/submit")
.param("tempMyentityPropName", "tempMyentityPropValue"))
.andExpect(status().is3xxRedirection()
.andExpect(redirectedUrl("/view"))
.andExpect(MockMvcResultMatchers.flash()
.attributeExists("MyCustomAttrName"))
.andExpect(MockMvcResultMatchers.flash()
.attributeExists("MyEntityAttrName"))//Or BindingResult...
.andReturn();
//Grab data from response to do something (or not)
MyCustomAttr custom = (MyCustomAttr) mv.getFlashMap().get("MyCustomAttrName");
MyEntity myentity = (MyEntity) mv.getFlashMap().get("MyEntityAttrName");
FlashMap flashMap = mv.getFlashMap();
String redirectUrl = mv.getResponse().getRedirectedUrl();
//Do the redirect call
mvc.perform(get(redirectUrl).flashAttrs(flashMap))
.andExpect(status().isOk())
.andExpect(view().name("eMyentityView"));
}
...
}