使用 REST-assured 获取并断言响应数据

简介: 使用 REST-assured 获取并断言响应数据

1. 概览

在本文中我们将讨论如何使用 REST-assured 测试 RESTful 服务,并重点关注如何获取和校验 REST APIs 的响应。

2. 测试类设置

在之前的文章中已经讨论过了 REST-assured 的基本使用,并展示了如何操作请求头、cookie 和 请求参数。

在现有的基础上,我们添加了一个简单的 REST 控制器 AppController,它在内部调用服务 AppService。我们将在测试示例中使用这些类。

要创建测试类,我们需要做更多的设置。由于我们在 classpath 中有 spring-boot-starter-test 依赖,所以我们可以轻松地使用 spring Testing 来测试。

首先,让我们创建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;
     //test cases
}
复制代码

在这个 JUnit 测试中,我们用几个 Spring 注解来标注我们的类,这些注解会在本地随机选取可用的端口启动应用程序。在 @PostConstruct 中,我们获取了完整 URI 来进行 REST 接口调用。

我们还在 AppService 上使用了 @MockBean,因为我们需要模拟这个类上的方法调用。

3. 断言 JSON 响应

JSON 是 REST API 中用于交换数据的最常见格式。响应可以由单个 JSON 对象或 JSON 对象数组组成。我们将在本节中见到这两种类型。

3.1 单个 JSON 对象

假设我们需要测试 /movie/{id},如果找到,它将返回一个 movie JSON 对象。 我们将使用 Mockito 框架模拟 AppService 调用以返回一些数据:

@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());
}
复制代码

上述代码中我们首先模拟了 appService.findMovie(1) 调用返回一个 Movie 对象。然后,我们在 REST-assured 的 get() 方法中构造了 REST URL,实现 GET 请求。最后,我们做了四个断言。

首先,我们检查了响应码,然后检查了 body 的内容。我们使用 Hamcrest 来断言预期值。

还要注意,如果响应 JSON 是嵌套的,我们可以使用点操作符 “key1.key2.key3” 来获取嵌套的键的值。

3.2 校验之后提取 JSON 响应

在某些情况下,我们可能需要在断言之后在提取响应内容,以便对其执行其他操作。我们可以使用extract() 方法提取 JSON 响应为一个类:

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

上述代码中我们使用 REST-assured 直接提取 JSON 响应为一个 Movie 对象并对它进行断言。

我们也可以提取整个 JSON 响应为一个字符串,使用 extract().asString() 方法:

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

我们也可以从 JSON 响应中提取特定的部分内容。

让我们看一个 POST API的测试,它需要一个 Movie 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() 方法从返回的 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));
}
复制代码

我们再次首先 模拟了 appService.getAll(),并发出请求。然后我们断言了 statusCode 和响应数组的大小。

这同样可以通过提取 JSON 响应内容完成:

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

4. 校验 Headers 和 Cookies

我们也可以对响应的 Headers 和 Cookies 进行断言:

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

同样可以单独提取 headers 和 Cookies 的内容:

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);
复制代码

这里,我们首先模拟了 appService.getFile(1) 返回 src/test/resources 路径中的文本文件。然后,我们调用服务并提取响应中的 byte[] ,然后断言该响应具有预期值。

6. 总结

在本文中,我们研究了使用 REST-assured 从 REST API 获取和验证响应的不同方式。

本文中的代码可以在 Github上获得。


相关文章
|
6月前
|
JSON 网络协议 API
PRC和HTTP(rest)过程的区别
PRC和HTTP(rest)过程的区别
|
2月前
|
Shell
HTTP状态码解析:在Haskell中判断响应成功与否
HTTP状态码解析:在Haskell中判断响应成功与否
|
3月前
automate Flow中如何用HTTP,POST的方式发送短信?
automate Flow中如何用HTTP,POST的方式发送短信?
42 2
|
3月前
|
数据采集 存储 监控
Haskell爬虫中日志记录:监控HTTP请求与响应
Haskell爬虫中日志记录:监控HTTP请求与响应
|
3月前
|
安全 API
Haskell HTTP请求:如何解读响应状态
Haskell HTTP请求:如何解读响应状态
|
5月前
|
前端开发 中间件 API
中间件API 请求和响应
【6月更文挑战第13天】
48 3
|
4月前
|
缓存 JSON 算法
http【详解】状态码,方法,接口设计 —— RestfuI API,头部 —— headers,缓存
http【详解】状态码,方法,接口设计 —— RestfuI API,头部 —— headers,缓存
71 0
|
JSON 架构师 前端开发
REST API 设计最佳实践:如何正确使用 HTTP 状态码?
本文分享在设计 REST API 时的最佳实践。关于设计优秀REST API 的一些建议、提示和指导,帮助您让消费者(以及开发人员)满意。 我们都应该努力使API变得易于使用。无论是对于消费者,还是我们自己的开发人员同伴。希望这篇文章能帮助你学到一些技巧,并激发出构建更好REST API的方法。
766 0
REST API 设计最佳实践:如何正确使用 HTTP 状态码?
|
JSON 前端开发 网络架构
DRF--请求和响应
DRF--请求和响应
|
JSON 网络架构 数据格式
通过 REST 请求体|学习笔记
快速学习通过 REST 请求体。
通过 REST 请求体|学习笔记