如何在@SpringBootTest中使用重定向来测试POST请求表单提交

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

我正在彻底学习Spring Boot,我已经接近尾声了,这似乎是最后一个症结点。

我觉得我没有得到的是那些如此简单和直接的事情之一,它甚至没有解释。

无论如何,我有一个简单的 CRUD 演示,其中有一个表单,用于创建硬编码的实体,一旦我提交表单,就会重定向到显示创建的新实体的页面。

它在多次测试的网络浏览器和邮递员中完美运行,但由于某种原因,当我执行@WebMvcTest和@SpringBootTest时,我得到了正确的302响应状态,但重定向响应中没有响应主体。

我确实读过这个问题: https://stackoverflow.com/a/45555607/21505152

即使主要文档也缺少任何信息: https://docs.spring.io/spring-framework/reference/testing/spring-mvc-test-framework/vs-end-to-end-integration-tests.html

这基本上表明 MockMvc 可能无法测试此类场景,如果是这样,有什么替代方案? 我还需要测试这个吗?

发生什么事了?因为一切都在浏览器中完美运行

这是代码:

@Controller
@RequestMapping("/dummy-entities")
public class DummyEntityController {

    private DummyEntityDao dao;

    public DummyEntityController(DummyEntityDao dao) {
        this.dao = dao;
    }

    @GetMapping("")
    public String getAll(Model model) {
        model.addAttribute("mainHeading", "Dummy Entities");
        model.addAttribute("dummyEntities", dao.getDummyEntities());
        return "dummyentities/dummy-entities";
    }

    @GetMapping("/{id}")
    public String getById(@PathVariable int id, Model model) {
        try {
            model.addAttribute("dummyEntity", dao.getDummyEntityById(id));
            return "dummyentities/dummy-entity";
        }catch (DummyEntityNotFoundException e) {
            throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage());
        }
    }

    @GetMapping("/add")
    public String getAddDummyEntityView() {
        return "dummyentities/add";
    }

    @PostMapping("/add")
    public String addDummyEntity(@ModelAttribute DummyEntity dummyEntity) {
        DummyEntity newDummyEntity = dao.createDummyEntity(dummyEntity);
        return "redirect:/dummy-entities/" + newDummyEntity.getId();
    }

    @GetMapping("/edit/{id}")
    public String getEditDummyEntityView(@PathVariable int id, Model model) {
        try {
            DummyEntity dummyEntity = dao.getDummyEntityById(id);
            model.addAttribute("dummyEntity", dummyEntity);
            return "dummyentities/edit";
        }catch (DummyEntityNotFoundException e) {
            throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage());
        }
    }


    @PostMapping("/edit/{id}")
    public String editDummyEntity(@ModelAttribute DummyEntity dummyEntity) {
        try {
            dao.updateDummyEntityById(dummyEntity);
        }catch (DummyEntityWriteException e) {

        }

        return "redirect:/dummy-entities/" + dummyEntity.getId();
    }


    @RequestMapping("/delete/{id}")
    public String deleteDummyEntity(Model model, @PathVariable int id) {
        try {
            dao.deleteDummyEntityById(id);
            model.addAttribute("deletedDummyEntityId", id);
            return "dummyentities/delete";
        }catch (DummyEntityNotFoundException e) {
            throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage());
        }catch (DummyEntityWriteException e) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.getMessage());
        }
    }
    
}

class DummyEntityControllerIntegratedTest extends MvcThymeleafApplicationTests {


    @Test
    void createAddsOne() throws Exception {
        DummyEntity dummyEntity = new DummyEntity(0, "DE-13", "dek13", "dev13", 10, 20, 30);
        mockMvc.perform(
            MockMvcRequestBuilders.post("/dummy-entities/add")
                .param("name", "DE-13")
                .param("key", "dek13")
                .param("value", "dev13")
                .param("x", Integer.valueOf(10).toString())
                .param("y", Integer.valueOf(20).toString())
                .param("z", Integer.valueOf(30).toString())
        ).andExpect(result -> assertEquals(302, result.getResponse().getStatus()));
    }

    @Test
    void createRedirectsToDehome () throws Exception {
        DummyEntity dummyEntity = new DummyEntity(0, "DE-13", "dek13", "dev13", 10, 20, 30);
        Map<String, Object> model = mockMvc.perform(
             MockMvcRequestBuilders.post("/dummy-entities/add")
                .param("name", "DE-13")
                .param("key", "dek13")
                .param("value", "dev13")
                .param("x", Integer.valueOf(10).toString())
                .param("y", Integer.valueOf(20).toString())
                .param("z", Integer.valueOf(30).toString())
        ).andReturn().getModelAndView().getModel();

        DummyEntity newDummyEntity = (DummyEntity) model.get("dummyEntity");
        assertNotNull(newDummyEntity);
    }



}

它在浏览器中运行完美,但第二次测试失败。 在我看来,它正在被重定向,这意味着客户端应该再次向获取新 id 的端点发出请求,并且应该返回这个?

我没有尝试使用 RedirectAttributes,因为我不确定它是否必要,如果这模拟了一个新请求,那么当它到达控制器端点时,一切都应该正常进行?

我尝试调试,但我发现重定向的端点在测试期间永远不会被调用,但我认为它可以工作,因为浏览器中的最终结果是完美的,它只是在这些测试中不起作用,这是为什么?

我将不胜感激任何帮助

spring-boot spring-mvc testing http-redirect
1个回答
0
投票

您必须自己进行重定向。我为此创建了一个助手。

@Autowired
private MockMvc mvc;

@Test
void myMvcTest() throws Exception {
    MvcResult mvcResult = mvc.perform(
        MockMvcRequestBuilders
            .post("/dummy-entities/add")
            // ...
        ).andExpect(status().is(302)).andReturn();

    String responseBody = mvcResult.getResponse().getContentAsString();

    assertThat(responseBody.indexOf("Find a Text")).isPositive();
}

帮手

import static org.junit.jupiter.api.Assertions.fail;

import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;

public class MockMvcUtility {
    public static MvcResult performRedirect(MockMvc mvc, MvcResult mvcResult) {
        try {
            MockHttpServletRequestBuilder builder = MockMvcRequestBuilders
                .get(mvcResult.getResponse().getRedirectedUrl());
            
            return mvc.perform(builder).andReturn();
        } catch (Exception e) {
            fail(e.getMessage());
            return null;
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.