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

qzwqbdag  于 2023-10-24  发布在  Spring
关注(0)|答案(1)|浏览(204)

我正在使用Spring的RedirectViewRedirectAttributesaddFlashAttributes的Post-Redirect-Get控制器。重定向使用浏览器手动工作。然而,我无法使用TestRestTemplate测试此重定向到重定向控制器。即使我在其中设置HttpClientOption.ENABLE_REDIRECTSTestRestTemplate也不会执行重定向虽然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
   }
   ...
}
k2arahey

k2arahey1#

看起来Spring处理重定向的策略是做两个调用,无论你使用TestRestTemplate还是MockMvc。参见the github issue。鉴于此,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"));

      //Instead of using the andReturn() and grabbing data, it's probably possible to complete the second perform directly with linked functions.

  }
  ...

}
根据Spring documentation,使用MockMvc分析表单有两种选择。您可以使用HtmlUnit或Selenium的WebDriver。WebDriver已经退出了一些功能,MockMvc应该提供Thymeleaf和其他视图响应(但可能不是jsp)。文档解释了如何将这些工具集成到您的测试中。

相关问题