使用MockMvc进行Spring控制器测试的POST方法

21

我正在尝试测试我的Spring Boot应用程序中控制器的一种方法。这是一个post端点,它在请求中获取一个id,并将该id传递给一个服务:

@Slf4j
@Controller
public class AdministrationController {

    private final AdministrationService administrationService;

    @Autowired
    public AdministrationController(AdministrationService administrationService) {
        this.administrationService = administrationService;
    }

    @PostMapping("/administration")
    public @ResponseBody ResponseEntity<String> deleteByMessageId(String id) {
        return new ResponseEntity<>(administrationService.deleteMessageById(id), HttpStatus.OK);
    }
}

这个控制器方法的测试:

RunWith(SpringRunner.class)
@WebMvcTest(AdministrationController.class)
public class AdministrationControllerTest {

    @Autowired
    private MockMvc mvc;

    @MockBean
    private AdministrationService service;

    @Test
    public void 
    deleteByMessageId_whenCalled_thenServiceMethodIsCalledWithRequestParameters() throws Exception {

        Object randomObj = new Object() {
            public final String id = "1234";
        };

        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writeValueAsString(randomObj);


        MvcResult result = mvc.perform(
            post("/administration")
                    .contentType(MediaType.APPLICATION_JSON)
                    .content(json))
            .andExpect(status().isOk())
            .andReturn();

        verify(service, times(1)).deleteMessageById("1234");
}

运行这个测试时,会执行Post请求,但是请求体为空:

MockHttpServletRequest:
  HTTP Method = POST
  Request URI = /administration
   Parameters = {}
      Headers = {Content-Type=[application/json]}
         Body = <no character encoding set>
Session Attrs = {}

似乎即使我在我的测试中设置了内容,它也没有出现在我发送的请求中。 而且,实际上,测试失败了:

Argument(s) are different! Wanted: "1234"
Actual invocation has different arguments: null

我在这里缺少什么?如何使用MockMvc设置请求正文?

4个回答

53

尝试使用.characterEncoding("utf-8"))

MvcResult result = mvc.perform(post("/administration")
    .contentType(MediaType.APPLICATION_JSON)
    .content(json)
    .characterEncoding("utf-8"))
    .andExpect(status().isOk())
    .andReturn();

顺序必须是characterEncoding、content、contentType。 - Lee Meador
1
你确定吗?我认为这没关系。 - stelios.anastasakis
我记得我的IDE似乎很在意那个顺序,虽然我没有检查过。但是这个顺序确实有效。 - Lee Meador
4
我明白Lee Meador的意思了。顺序无所谓,问题在于您的代码中有一个多余的括号或者缺失一个括号。在mvc.perform()结束后再使用.andExpect(),而不是将.andExpect()与post()链接在一起。我刚刚也碰到了这个问题。 - DP Park

3
另一个选项(受@stelios-anastasakis回答启发)是在Content-Type头中提供字符编码:
MvcResult result = mvc.perform(post("/administration")
    .contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
    .content(json)
    .andExpect(status().isOk())
    .andReturn();

请注意,这里我们使用MediaType.APPLICATION_JSON_UTF8_VALUE而不是MediaType.APPLICATION_JSON

8
APPLICATION_JSON_UTF8_VALUE 已经被废弃。 - TuGordoBello

0
        mockMvc.perform(post( "/request")
                .content(objectMapper.writeValueAsString(requestBody))
                .contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
                .andDo(print())
                .andExpect(status().isOk());

-1

你肯定忘了为你的方法参数添加注解。

public @ResponseBody ResponseEntity<String> deleteByMessageId(String id)

应该是这样的:
public @ResponseBody ResponseEntity<String> deleteByMessageId(@RequestParam("id") String id)

如果您想将其用作请求参数,请查看此处的Spring MVC文档。当然,编写测试取决于您对此处id的期望方式。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接