【问题标题】:How to integration test a RESTful APIs PUT endpoint with TestRestTemplate?如何使用 TestRestTemplate 集成测试 RESTful APIs PUT 端点?
【发布时间】:2020-06-30 17:30:59
【问题描述】:

我目前正在开发一个 Spring Boot CRUD RESTful API,它的 User 实体由两个参数组成:nameid。它的端点是:

  • 在 /users 中发布请求 - 创建用户
  • GET REQUEST IN /users/{id} - 按 id 列出特定用户
  • GET REQUEST IN /users - 列出所有用户
  • PUT REQUEST IN /users/{id} - 通过其 id 更新特定用户
  • DELETE REQUEST IN /users/{id} - 按 id 删除特定用户

每个端点都使用一个控制器和一个服务来实现其逻辑。

我已经为我的控制器和服务编写了单元测试,现在我正在尝试构建集成测试来断言我的端点作为一组组件可以正常工作。

不涉及任何模拟,所有这些都将通过使用 TestRestTemplate 来完成,并断言每个操作都已正确执行,并且每个响应都检查了其预期值。

以下是我已经构建的测试:

@SpringBootTest(classes = UsersApiApplication.class,
        webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class UserControllerTest {

    @LocalServerPort
    private int port;

    TestRestTemplate restTemplate = new TestRestTemplate();
    HttpHeaders headers = new HttpHeaders();

    private void instantiateNewUser() {
        User userNumberFour = new User();
        userNumberFour.setName("Four");
        userNumberFour.setId(4L);

        ResponseEntity<User> responseEntity = restTemplate
                .postForEntity(createURLWithPort("/users"), userNumberFour, User.class);
    }

    @Test
    public void createNewUserTest() {
        User testUser = new User();
        testUser.setName("Test User");
        testUser.setId(5L);

        ResponseEntity<User> responseEntity = restTemplate
                .postForEntity(createURLWithPort("/users"), testUser, User.class);

        assertEquals(201, responseEntity.getStatusCodeValue());
        assertEquals(responseEntity.getBody(), testUser);
    }


    @Test
    public void listSpecificUserTest() throws JSONException {

        instantiateNewUser();
        HttpEntity<String> httpEntity = new HttpEntity<String>(null, headers);

        ResponseEntity<String> responseEntity = restTemplate.exchange(
                createURLWithPort("/users/4/"),
                HttpMethod.GET, httpEntity, String.class);

        String expectedResponseBody = "{id:4,name:Four}";

        assertEquals(200, responseEntity.getStatusCodeValue());
        JSONAssert.assertEquals(expectedResponseBody, responseEntity.getBody(), false);
    }

    @Test
    public void listAllUsersTest() throws JSONException {

        instantiateNewUser();
        HttpEntity<String> httpEntity = new HttpEntity<String>(null, headers);

        ResponseEntity<String> responseEntity = restTemplate.exchange(
                createURLWithPort("/users"),
                HttpMethod.GET, httpEntity, String.class);

        //All instantiated users
        ArrayList<String> expectedResponseBody = new ArrayList<>(Collections.emptyList());
        expectedResponseBody.add("{id:1,name:Neo}");
        expectedResponseBody.add("{id:2,name:Owt}");
        expectedResponseBody.add("{id:3,name:Three}");
        expectedResponseBody.add("{id:4,name:Four}");

        assertEquals(200, responseEntity.getStatusCodeValue());
        JSONAssert.assertEquals(String.valueOf(expectedResponseBody), responseEntity.getBody(), false);
    }

    @Test
    public void deleteSpecificUserTest() throws JSONException {

        instantiateNewUser();
        HttpEntity<String> httpEntity = new HttpEntity<String>(null, headers);

        ResponseEntity<String> responseEntity = restTemplate.exchange(
                createURLWithPort("/users/4/"),
                HttpMethod.DELETE, httpEntity, String.class);

        assertEquals(204, responseEntity.getStatusCodeValue());
        JSONAssert.assertEquals(null, responseEntity.getBody(), false);
    }

    private String createURLWithPort(String uri) {
        return "http://localhost:" + port + uri;
    }
}

如您所见,它缺少 PUT 请求方法测试,即更新端点。 为了实现它的逻辑,我需要发送一个包含将覆盖旧用户特征的内容的消息正文,但是如何?

这是我到目前为止所做的:

    @Test
    public void updateSpecificUserTest() throws JSONException {
    
        instantiateNewUser();
        HttpEntity<String> httpEntity = new HttpEntity<String>(null, headers);
    
        ResponseEntity<String> responseEntity = restTemplate.exchange(
                createURLWithPort("/users/4/"),
                HttpMethod.PUT, httpEntity, String.class);

        String expectedResponseBody = "{id:4,name:Four Updated}";
    
        assertEquals(200, responseEntity.getStatusCodeValue());
        JSONAssert.assertEquals(expectedResponseBody, responseEntity.getBody(), false);
    }
    

如果有人可以帮助解决这个问题,将不胜感激,但在网上没有找到答案。

【问题讨论】:

    标签: java spring spring-boot testing integration-testing


    【解决方案1】:
    HttpEntity<String> httpEntity = new HttpEntity<String>(null, headers);
    

    您已将正文发送为空。你也可以使用 mockMvc,它是比 rest 模板更好的方法。

    User testUser = new User();
    testUser.setName("Test User");
    HttpEntity<String> httpEntity = new HttpEntity<String>(testUser, headers);
    

    https://howtodoinjava.com/spring-boot2/testing/spring-boot-mockmvc-example/

    【讨论】:

    • 感谢您的回复。 MockMvc 更适合单元测试,因为它模拟 HTTP 请求和响应,因此它的范围只是应用程序的 MVC 部分。使用 TestRestTemplate,我能够测试我的应用程序的真实实例,这就是我在集成测试中使用它的原因。关于正文,这确实是问题的原因,但是该代码不起作用,因为 httpEntity 只接受字符串参数并且您定义的 testUser 是 User 类型。
    • 只需要使用ObjectMapper将POJO转成String
    • 我认为这是正确的路径,但我仍然收到 415 响应错误,这意味着媒体类型不受支持。如何将我的正文请求类型设置为 JSON?
    【解决方案2】:

    所以,我的问题的真正解决方案是我在我的 httpEntity 中发送了一个空请求正文。

    我还需要将内容类型设置为 JSON:

    @Test
        public void updateSpecificUserTest() throws JSONException, JsonProcessingException {
    
            instantiateNewUser();
    
            User updatedUser = new User();
            updatedUser.setName("Updated");
            updatedUser.setId(4L);
    
            ObjectMapper mapper = new ObjectMapper();
            String requestBody = mapper.writeValueAsString(updatedUser);
    
            headers.setContentType(MediaType.APPLICATION_JSON);
    
            HttpEntity<String> httpEntity = new HttpEntity<String>(requestBody, headers);
    
            ResponseEntity<String> responseEntity = restTemplate.exchange(
                    createURLWithPort("/users/4/"),
                    HttpMethod.PUT, httpEntity, String.class);
    
            String expectedResponseBody = "{id:4,name:Updated}";
    
            assertEquals(200, responseEntity.getStatusCodeValue());
            JSONAssert.assertEquals(expectedResponseBody, responseEntity.getBody(), false);
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-12
      • 1970-01-01
      • 2018-02-21
      • 2017-09-09
      • 2017-06-02
      • 1970-01-01
      相关资源
      最近更新 更多