1. 概述

本教程将重点介绍如何使用 REST-assured 来测试 REST 服务,特别是如何 捕获并验证 REST API 的响应数据

2. 测试类的准备工作

在之前的教程中,我们已经对 REST-assured 做了基础介绍,也展示了如何操作请求 headers、cookies 和参数

基于已有基础,我们新增了一个简单的 REST 控制器 AppController,它内部调用一个服务类 AppService。在测试示例中,我们将使用这两个类。

为了创建测试类,我们需要做些额外的配置。由于项目中已引入 spring-boot-starter-test,我们可以直接使用 Spring 的测试工具。

首先,创建一个测试类 AppControllerIntegrationTest 的基本结构:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class AppControllerIntegrationTest {

    @LocalServerPort
    private int port;

    private String uri;

    @PostConstruct
    public void init() {
        uri = "http://localhost:" + port;
    }

    @MockBean
    AppService appService;

     //测试用例
}

在这个 JUnit 测试类中,我们通过 Spring 的注解让应用在本地随机端口启动。在 @PostConstruct 方法中,我们构建了完整的请求 URI。

同时,我们使用 @MockBeanAppService 进行了 mock,以便控制其行为。

3. 验证 JSON 响应

JSON 是 REST API 中最常见的数据交换格式。响应可能是单个 JSON 对象,也可能是 JSON 数组。我们分别来看这两种情况。

3.1. 单个 JSON 对象

假设我们要测试 /movie/{id} 接口,当传入有效的 id 时,返回一个 Movie JSON 对象。

我们使用 Mockito 框架来模拟 AppService 的行为,让它返回一些 mock 数据:

@Test
public void givenMovieId_whenMakingGetRequestToMovieEndpoint_thenReturnMovie() {

    Movie testMovie = new Movie(1, "movie1", "summary1");
    when(appService.findMovie(1)).thenReturn(testMovie);

    get(uri + "/movie/" + testMovie.getId()).then()
      .assertThat()
      .statusCode(HttpStatus.OK.value())
      .body("id", equalTo(testMovie.getId()))
      .body("name", equalTo(testMovie.getName()))
      .body("synopsis", notNullValue());
}

上面的代码中,我们先 mock 了 appService.findMovie(1) 的返回值,然后使用 REST-assured 提供的 get() 方法构造请求,最后做了几项断言。

首先检查响应状态码,然后验证 body 中的字段值。我们使用了 Hamcrest 来进行断言。

⚠️ 如果响应是嵌套 JSON,可以通过 . 操作符访问内部字段,如 "key1.key2.key3"

3.2. 验证后提取 JSON 响应

有时候我们需要在验证之后提取响应数据,用于后续处理。

可以使用 extract() 方法将响应提取为一个类对象:

Movie result = get(uri + "/movie/" + testMovie.getId()).then()
  .assertThat()
  .statusCode(HttpStatus.OK.value())
  .extract()
  .as(Movie.class);
assertThat(result).isEqualTo(testMovie);

这里我们将响应提取为 Movie 对象,并进行了断言。

也可以将整个响应提取为字符串:

String responseString = get(uri + "/movie/" + testMovie.getId()).then()
  .assertThat()
  .statusCode(HttpStatus.OK.value())
  .extract()
  .asString();
assertThat(responseString).isNotEmpty();

还可以提取 JSON 中的某个字段:

@Test
public void givenMovie_whenMakingPostRequestToMovieEndpoint_thenCorrect() {
    Map<String, String> request = new HashMap<>();
    request.put("id", "11");
    request.put("name", "movie1");
    request.put("synopsis", "summary1");

    int movieId = given().contentType("application/json")
      .body(request)
      .when()
      .post(uri + "/movie")
      .then()
      .assertThat()
      .statusCode(HttpStatus.CREATED.value())
      .extract()
      .path("id");
    assertThat(movieId).isEqualTo(11);
}

这里我们构造了一个 POST 请求体,然后使用 path("id") 提取了返回 JSON 中的 id 字段。

3.3. JSON 数组

如果返回的是 JSON 数组,也可以进行验证:

@Test
public void whenCallingMoviesEndpoint_thenReturnAllMovies() {

Set<Movie> movieSet = new HashSet<>();
movieSet.add(new Movie(1, "movie1", "summary1"));
movieSet.add(new Movie(2, "movie2", "summary2"));
when(appService.getAll()).thenReturn(movieSet);

get(uri + "/movies").then()
    .statusCode(HttpStatus.OK.value())
    .assertThat()
    .body("size()", is(2));
}

我们先 mock 了 appService.getAll() 的返回值,然后验证响应数组的长度。

也可以通过提取的方式处理:

Movie[] movies = get(uri + "/movies").then()
  .statusCode(200)
  .extract()
  .as(Movie[].class);
assertThat(movies.length).isEqualTo(2);

4. 验证 Headers 和 Cookies

可以使用同名方法验证响应中的 header 和 cookie:

@Test
public void whenCallingWelcomeEndpoint_thenCorrect() {
    get(uri + "/welcome").then()
        .assertThat()
        .header("sessionId", notNullValue())
        .cookie("token", notNullValue());
}

也可以单独提取 header 和 cookie:

Response response = get(uri + "/welcome");

String headerName = response.getHeader("sessionId");
String cookieValue = response.getCookie("token");
assertThat(headerName).isNotBlank();
assertThat(cookieValue).isNotBlank();

5. 验证文件响应

如果 REST API 返回的是文件,可以使用 asByteArray() 提取响应:

File file = new ClassPathResource("test.txt").getFile();
long fileSize = file.length();
when(appService.getFile(1)).thenReturn(file);

byte[] result = get(uri + "/download/1").asByteArray();

assertThat(result.length).isEqualTo(fileSize);

我们首先 mock 了 appService.getFile(1) 返回一个位于 src/test/resources 路径下的文本文件。然后请求接口并提取为字节数组,最后验证其长度是否符合预期。

6. 总结

本教程介绍了使用 REST-assured 来捕获和验证 REST API 响应数据的多种方式,包括 JSON 对象、数组、headers、cookies 以及文件响应。

一如既往,本文代码可在 GitHub 获取。


原始标题:Getting and Verifying Response Data with REST-assured | Baeldung