Spring boot:RestTemplate POST 调用不返回创建的状态码

Posted

技术标签:

【中文标题】Spring boot:RestTemplate POST 调用不返回创建的状态码【英文标题】:Spring boot : RestTemplate POST call does not return created status code 【发布时间】:2020-11-20 03:18:27 【问题描述】:

我是 Spring Boot Rest 模板的新手。我正在尝试为休息模板发布调用编写单元测试用例。 我创建了一个用户控制器来发送虚拟数据。 为 POST 调用编写的用户控制器对单元测试是否正确?如果不是,那么正确的写法是什么?我从用户控制器返回的响应是否正确?我应该将状态码返回为 200 还是 201? 有人可以帮我吗?

下面是用户控制器

@PostMapping("/users")
    public User createUser(@RequestBody User user)
        List<String> messages = new ArrayList<>();
        messages.add("Hi");

        User createUser = new User();
        createUser.setId(1);
        createUser.setName("John");
        createUser.setAge(22);
        createUser.setMessages(messages);
        return user;
    

下面是调用后的单元测试用例:

@Test
    public void testSuccessPostUser() throws Exception
        String baseUrl = "http://localhost:8080/users";
        List<String> messages = new ArrayList<>();
        messages.add("Hi");

        User user = new User();
        user.setId(1);
        user.setName("John");
        user.setAge(22);
        user.setMessages(messages);

        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        httpHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));

        HttpEntity<User> httpEntity = new HttpEntity<>(user, httpHeaders);

        HttpHandler httpHandler = new HttpHandler();
        ResponseEntity<User>  actual = httpHandler.sendPost(baseUrl, httpHeaders, user, User.class);

        //verify request succeed
        assertEquals(HttpStatus.CREATED, actual.getStatusCode());
        assertEquals(201, actual.getStatusCodeValue());
        assertTrue(responseBody.contains(id);
    

【问题讨论】:

【参考方案1】:

首先,为了测试HTTP控制器你可以使用MockMvc

示例测试:

mockMvc.perform(post("/users")
       .contentType(MediaType.APPLICATION_JSON)
       .content(" "id": 1, "Name": "John", "Age": 22 ") 
       .accept(MediaType.APPLICATION_JSON))
       .andExpect(status().isCreated())
       .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
       .andExpect(jsonPath("$.id").value($id)) 
       .andExpect(jsonPath("$.value").value("some-value"));

更多详情docs

要返回 201 代码,您需要在控制器中添加 @ResponseStatus(HttpStatus.CREATED)

【讨论】:

如果我错了请纠正我,我们不使用mockMvc进行集成测试吗? 是的,这是正确的,但我认为你的情况是集成测试:) 我正在编写单元测试。正确的写法是什么? 您调用端点http://localhost:8080/users,如果它没有存根,您的测试类型是集成。 MockMvc 提供了一个优雅且易于使用的 API 来调用 Web 端点并同时检查和断言它们的响应。您必须添加 @ContextConfiguration@WebAppConfiguration 来测试以准备用于测试的 Spring 上下文。 我正在使用junit5编写单元测试用例。我正在使用@SpringBootTest 注释。我还需要@contextConfiguration@WebAppConfiguration 吗?另外,当您说为测试准备 spring 上下文时,它到底是什么意思?【参考方案2】:

如果你想返回自定义状态码,你应该返回RepsponseEntity

@PostMapping("/users")
public ResposneEntity<User> createUser(@RequestBody User user)
    ...
    return new ResponseEntity(user, HttpStatus.CREATED);

如果您想了解 POST 方法的正确 https 状态,我建议您阅读以下内容:What status code should we return if the POST succeeds but does not result in creating anything new?

【讨论】:

【参考方案3】:

POST 默认返回 200。

如果你想让它返回 201,添加这个:

@ResponseStatus(HttpStatus.CREATED)
@PostMapping("/users")
public User createUser(@RequestBody User user)

【讨论】:

以上是关于Spring boot:RestTemplate POST 调用不返回创建的状态码的主要内容,如果未能解决你的问题,请参考以下文章

Spring boot restTemplate

spring boot 注入 restTemplate

如何在 Java Spring boot 中模拟 RestTemplate?

使用注入 java 和 spring boot 的 RestTemplate 类进行单元测试

spring-boot Autowired DiscoveryClient RestTemplate UnknownHostException

(030)Spring Boot之RestTemplate访问web服务案例