使用 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上获得。


相关文章
jmeter:利用beanshell进行多重断言
在接口测试中,我们对返回结果的正确性判断一般是基于响应报文的返回内容进行断言。但有些时候,按照正常的业务逻辑来说,一个请求返回的内容是多种不同的。
jmeter:利用beanshell进行多重断言
|
Java Maven
IDEA 2021 整合 SSM 配置离线 Maven 3.8.1 报错大全 Since Maven 3.8.1 http repositories are blocked.
IDEA 2021 整合 SSM 配置离线 Maven 3.8.1 报错大全 Since Maven 3.8.1 http repositories are blocked.
7593 0
IDEA 2021 整合 SSM 配置离线 Maven 3.8.1 报错大全 Since Maven 3.8.1 http repositories are blocked.
|
IDE 网络协议 安全
阿里Java编程规约【九】 注释规约
1.【强制】类、类属性、类方法的注释必须使用 Javadoc 规范,使用 /** 内容 */ 格式,不得使用 // xxx 方式。 说明:在 IDE 编辑窗口中,Javadoc 方式会提示相关注释,生成 Javadoc 可以正确输出相应注释;在 IDE 中,工程调用方法时,不进入方法即可悬浮提示方法、参数、返回值的意义,提高阅读效率。
2054 0
|
Java 编译器 Spring
面试突击78:@Autowired 和 @Resource 有什么区别?
面试突击78:@Autowired 和 @Resource 有什么区别?
16261 6
|
XML JavaScript Java
【JAVA XML 探秘】DOM、SAX、StAX:揭秘 Java 中 XML 解析技术的终极指南!
【8月更文挑战第25天】本文详细探讨了Java中三种主流的XML解析技术:DOM、SAX与StAX。DOM将XML文档转换为树状结构,便于全方位访问和修改;SAX采取事件驱动模式,适用于大型文件的顺序处理;StAX则兼具DOM和SAX的优点,支持流式处理和随机访问。文中提供了每种技术的示例代码,帮助读者理解如何在实际项目中应用这些解析方法。
619 1
EMQ
|
安全 开发工具 数据安全/隐私保护
MQTT 5.0 报文解析 06:AUTH
MQTT 5.0 引入了增强认证特性,它使 MQTT 除了简单密码认证和 Token 认证以外,还能够支持质询/响应风格的认证。为了实现这一点,它在原先 CONNECT 和 CONNACK 报文的基础上,又引入了 AUTH 报文来实现任意多次的认证数据交换,以支持各种不同类型的认证机制,例如 SCRAM、Kerberos 认证等等。
EMQ
489 78
MQTT 5.0 报文解析 06:AUTH
Java代码解释++i和i++的五个主要区别
本文介绍了前缀递增(++i)和后缀递增(i++)的区别。两者在独立语句中无差异,但在赋值表达式中,i++ 返回原值,++i 返回新值;在复杂表达式中计算顺序不同;在循环中虽结果相同但使用方式有别。最后通过 `Counter` 类模拟了两者的内部实现原理。
Java代码解释++i和i++的五个主要区别
|
SQL 前端开发 数据库
逻辑删除数据库中的数据。
这篇文章介绍了逻辑删除和物理删除的概念与区别,并详细演示了如何在数据库中实现逻辑删除,包括在表中添加一个表示删除状态的字段,并通过修改该字段的值来实现数据的逻辑删除,同时提供了相应的SQL语句、DAO层、Service层和Controller层的代码示例以及前端页面的展示。
逻辑删除数据库中的数据。
|
XML Java API
Java实现XML格式化
Java实现XML格式化
581 0
|
Web App开发 机器学习/深度学习 人工智能
详细解读AI测试之Applitools入门教程
详细解读AI测试之Applitools入门教程
765 0