Spring TestRestTemplate postForEntity 即使设置了 HttpClientOption.ENABLE_REDIRECTS 也不会进行重定向

问题描述 投票:0回答:1

我将 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 请求), 请描述一下。
  • 如果有不同的方式获取TestRestTemplate 允许/完成重定向,它是什么?
  • 如果没有办法做到这一点 (最不推荐),是否至少有一种配置方法 TestRestTemplate 返回 flashAttributes,以便我可以在单独的 get 中使用它们 调用 ResponseEntity 标头中返回的位置?

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-mvc testing redirect post get
1个回答
0
投票

看起来 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"));



  }
  ...

}

© www.soinside.com 2019 - 2024. All rights reserved.