进阶用法

验证响应数据

您还可以验证状态码,状态行,Cookie,headers,内容类型和正文。

响应体断言

json 格式断言

假设某个 get 请求 (http://localhost:8080/lotto) 返回 JSON 如下:

{
"lotto":{
 "lottoId":5,
 "winning-numbers":[2,45,34,23,7,5,3],
 "winners":[{
   "winnerId":23,
   "numbers":[2,45,34,23,3,5]
 },{
   "winnerId":54,
   "numbers":[52,3,12,11,18,22]
 }]
}
}

REST assured 可以帮您轻松地进行 get 请求并对响应信息进行处理。

  • 断言 lottoId 的值是否等于 5,示例:
get("/lotto").then().body("lotto.lottoId", equalTo(5));
  • 断言 winnerId 的取值包括 23 和 54,示例:
get("/lotto").then().body("lotto.winners.winnerId", hasItems(23, 54));

提醒一下:equalTohasItems是 Hamcrest matchers 提供的方法,所以需要静态导入入 org.hamcrest.Matchers

xml 格式断言

XML 可以一种通过简单的方式解析。假设一个 POST 请求http://localhost:8080/greetXML返回:

<greeting>
   <firstName>{params("firstName")}</firstName>
   <lastName>{params("lastName")}</lastName>
</greeting>
  • 断言 firstName 是否返回正确,示例:
given().
         parameters("firstName", "John", "lastName", "Doe").
when().
         post("/greetXML").
then().
         body("greeting.firstName", equalTo("John")).
  • 同时断言 firstname 和 lastname 是否返回正确,示例:
given().
         parameters("firstName", "John", "lastName", "Doe").
when().
         post("/greetXML").
then().
         body("greeting.firstName", equalTo("John")).
         body("greeting.lastName", equalTo("Doe"));
with().parameters("firstName", "John", "lastName", "Doe")
.when().post("/greetXML")
.then().body("greeting.firstName", equalTo("John"), "greeting.lastName", equalTo("Doe"));
  • 断言 cookie 的值是否等于 cookieValue,示例:
get("/x").then().assertThat().cookie("cookieName", "cookieValue")
  • 同时断言 多个 cookie 的值是否等于 cookieValue,示例:
get("/x").then()
.assertThat().cookies("cookieName1", "cookieValue1", "cookieName2", "cookieValue2")
  • 断言 cookie 的值是否包含 cookieValue,示例:
get("/x").then()
.assertThat().cookies("cookieName1", "cookieValue1", "cookieName2", containsString("Value2"))

状态码 Status Code 断言

  • 断言 状态码是否等于 200,示例:
get("/x").then().assertThat().statusCode(200)
  • 断言 状态行是否为 something,示例:
get("/x").then().assertThat().statusLine("something")
  • 断言 状态行是否包含 some,示例:
get("/x").then().assertThat().statusLine(containsString("some"))

Header 断言

  • 断言 Header 的值是否等于 HeaderValue,示例:
get("/x").then().assertThat().header("headerName", "headerValue")
  • 同时断言 多个 Header 的值是否等于 HeaderValue,示例:
get("/x").then()
.assertThat().headers("headerName1", "headerValue1", "headerName2", "headerValue2")
  • 断言 Header 的值是否包含 HeaderValue,示例:
get("/x").then()
.assertThat().headers("headerName1", "headerValue1", "headerName2", containsString("Value2"))
  • 断言 Header 的“Content-Length”小于 1000,示例:

可以先使用映射函数首先将头值转换为 int,然后在使用 Hamcrest 验证前使用“整数”匹配器进行断言:

get("/something").then()
.assertThat().header("Content-Length", Integer::parseInt, lessThan(1000));

Content-Type 断言

  • 断言 Content-Type 的值是否等于 application/json,示例:
get("/x").then().assertThat().contentType(ContentType.JSON)

内容全匹配断言

  • 断言 响应体是否完全等于 something,示例:
get("/x").then().assertThat().body(equalTo("something"))

响应时间断言

REST Assured 2.8.0 开始支持测量响应时间,例如:

long timeInMs = get("/lotto").time()

或使用特定时间单位:

long timeInSeconds = get("/lotto").timeIn(SECONDS);

其中 SECONDS 只是一个标准的 TimeUnit。您还可以使用 DSL 验证:

when().
      get("/lotto").
then().
      time(lessThan(2000L)); // Milliseconds

when().
      get("/lotto").
then().
      time(lessThan(2L), SECONDS);

需要注意的是,您只能参考性地将这些测量数据与服务器请求处理时间相关联(因为响应时间将包括 HTTP 往返和 REST Assured 处理时间等,不能做到十分准确)。

文件上传

通常我们在向服务器传输大容量的数据时,比如文件时会使用 multipart 表单数据技术。 rest-assured 提供了一种multiPart方法来辨别这究竟是文件、二进制序列、输入流还是上传的文本。

  • 表单中上只传一个文件,示例:
given().
        multiPart(new File("/path/to/file")).
when().
        post("/upload");
  • 存在 control 名的情况下上传文件,示例:
given().
        multiPart("controlName", new File("/path/to/file")).
when().
        post("/upload");
  • 同一个请求中存在多个"multi-parts"事务,示例:
byte[] someData = ..
given().
        multiPart("controlName1", new File("/path/to/file")).
        multiPart("controlName2", "my_file_name.txt", someData).
        multiPart("controlName3", someJavaObject, "application/json").
when().
        post("/upload");
  • MultiPartSpecBuilder 用法,示例:

更多使用方法可以使用MultiPartSpecBuilder

Greeting greeting = new Greeting();
greeting.setFirstName("John");
greeting.setLastName("Doe");

given().
        multiPart(new MultiPartSpecBuilder(greeting, ObjectMapperType.JACKSON_2)
                .fileName("greeting.json")
                .controlName("text")
                .mimeType("application/vnd.custom+json").build()).
when().
        post("/multipart/json").
then().
        statusCode(200);
  • MultiPartConfig 用法,示例:

MultiPartConfig可用来指定默认的 control 名和文件名

given().config(config().multiPartConfig(multiPartConfig()
.defaultControlName("something-else")))  

默认把 control 名配置为"something-else"而不是"file"。 更多用法查看 博客介绍

Logging 日志

当我们在编写接口测试脚本的时候,我们可能需要在测试过程中打印一些日志,以便于我们在测试过程中查看接口的请求和响应信息,以及一些其他的信息。RestAssured 提供了一些方法来打印日志,我们可以根据需要选择合适的方法来打印日志。

  • RestAssured 提供了一个全局的日志配置方法,可以在测试开始前配置日志,然后在测试过程中打印日志。这种方法适用于所有的测试用例,但是它只能打印请求和响应的信息,不能打印其他的信息。

  • RestAssured 还提供了一个局部的日志配置方法,可以在测试过程中打印日志。这种方法可以打印请求和响应的信息,也可以打印其他的信息。

全局日志配置

添加全局日志步骤
  • 引入日志相关的依赖类
import io.restassured.config.LogConfig;
import io.restassured.filter.log.LogDetail;
import io.restassured.filter.log.RequestLoggingFilter;
import io.restassured.filter.log.ResponseLoggingFilter;
  • 在 setup() 方法中添加日志配置

使用 LogConfig 配置,启用了请求和响应的日志记录,以及启用了漂亮的输出格式。启用了请求和响应的日志记录过滤器,这将记录请求和响应的详细信息。

// 启用全局请求和响应日志记录
        RestAssured.config = RestAssured.config()
                .logConfig(LogConfig.logConfig()
                        .enableLoggingOfRequestAndResponseIfValidationFails(LogDetail.ALL)
                        .enablePrettyPrinting(true));
  • 在 setup() 方法中启用了全局日志记录过滤器
// 启用全局请求和响应日志记录过滤器
    RestAssured.filters(new RequestLoggingFilter(), new ResponseLoggingFilter());
全局日志代码示例
package com.example;

import io.restassured.RestAssured;
// 引入日志相关的类
import io.restassured.config.LogConfig;
import io.restassured.filter.log.LogDetail;
import io.restassured.filter.log.RequestLoggingFilter;
import io.restassured.filter.log.ResponseLoggingFilter;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.equalTo;

public class TestDemo {

    @BeforeClass
    public void setup() {
        // 启用全局请求和响应日志记录
        RestAssured.config = RestAssured.config()
                .logConfig(LogConfig.logConfig()
                        .enableLoggingOfRequestAndResponseIfValidationFails(LogDetail.ALL)
                        .enablePrettyPrinting(true));
        // 启用全局请求和响应日志记录过滤器
        RestAssured.filters(new RequestLoggingFilter(), new ResponseLoggingFilter());
    }

    @Test(description = "Verify that the Get Post API returns correctly")
    public void verifyGetAPI() {
      // 测试用例已省略,可参考 demo
    }

    @Test(description = "Verify that the publish post API returns correctly")
    public void verifyPostAPI() {
      // 测试用例已省略,可参考 demo
    }
}
查看全局日志输出
  • 打开本项目的 Terminal 窗口,执行以下命令运行测试脚本
  • 查看日志输出

log-sceenshot1

局部日志配置

在 RestAssured 中,你可以进行局部日志配置,以便在特定的测试方法或请求中启用或禁用日志记录,而不影响全局配置。

添加日志步骤
  • 在想要打印日志的测试方法中启用了添加日志配置,示例:
    @Test(description = "Verify that the Get Post API returns correctly")
    public void verifyGetAPI() {

        // Given
        given()
                .log().everything(true)  // 输出 request 相关日志
                .baseUri("https://jsonplaceholder.typicode.com")
                .header("Content-Type", "application/json")

                // When
                .when()
                .get("/posts/1")

                // Then
                .then()
                .log().everything(true)  // 输出 response 相关日志
                .statusCode(200)
    }
查看局部日志输出
  • 打开本项目的 Terminal 窗口,执行以下命令运行测试脚本
  • 查看日志输出

report1

LogConfig 配置说明

在 RestAssured 中,你可以使用 LogConfig 类来配置请求和响应的日志记录。LogConfig 允许你定义日志详细程度、输出格式、输出位置等。以下是一些常见的 LogConfig 配置示例:

  1. 启用请求和响应的日志记录:

    RestAssured.config = RestAssured.config()
        .logConfig(LogConfig.logConfig()
        .enableLoggingOfRequestAndResponseIfValidationFails(LogDetail.ALL));
    

    这将启用请求和响应的日志记录,只有当验证失败时才记录。

  2. 配置输出级别:

    RestAssured.config = RestAssured.config()
        .logConfig(LogConfig.logConfig()
        .enableLoggingOfRequestAndResponseIfValidationFails(LogDetail.HEADERS));
    

    这将只记录请求和响应的头部信息。

  3. 配置输出位置:

    RestAssured.config = RestAssured.config()
        .logConfig(LogConfig.logConfig()
        .enableLoggingOfRequestAndResponseIfValidationFails(LogDetail.ALL)
            .enablePrettyPrinting(true)
            .defaultStream(FileOutputStream("log.txt")));
    

    这将日志记录输出到名为 “log.txt” 的文件。

  4. 配置漂亮的输出格式:

    RestAssured.config = RestAssured.config()
        .logConfig(LogConfig.logConfig()
        .enableLoggingOfRequestAndResponseIfValidationFails(LogDetail.ALL)
            .enablePrettyPrinting(true));
    

    这将启用漂亮的输出格式,使日志更易于阅读。

你可以根据你的具体需求组合这些配置选项,并将其设置为 RestAssured.config 以配置全局的请求和响应日志记录。这将有助于在 RestAssured 中记录和审查请求和响应,以便调试和分析问题。

Request Logging 请求日志记录

从版本 1.5 开始,REST Assured 支持在使用 RequestLoggingFilter 将请求规范发送到服务器之前记录请求规范。请注意,HTTP Builder 和 HTTP Client 可能会添加日志中打印的内容之外的其他标头。筛选器将仅记录请求规范中指定的详细信息。也就是说,您不能将 RequestLoggingFilter 记录的详细信息视为实际发送到服务器的详细信息。此外,后续筛选器可能会在日志记录发生后更改请求。如果您需要记录网络上实际发送的内容,请参阅 HTTP 客户端日志记录文档或使用外部工具,例如 Wireshark。

示例:

given().log().all()   // 记录所有请求规范细节,包括参数、标头和正文
given().log().params()   // 只记录请求的参数
given().log().body()   // 只记录请求正文
given().log().headers()   // 只记录请求头
given().log().cookies()   // 只记录请求 cookies
given().log().method()   // 只记录请求方法
given().log().path()   // 只记录请求路径

Response Logging 响应日志记录

  • 只想要打印响应正文,而不考虑状态代码,可以执行以下操作, 示例:
get("/x").then().log().body()
  • 不管是否发生错误,都将打印响应正文。如果只对在发生错误时打印响应正文感兴趣,示例:
get("/x").then().log().ifError()
  • 在响应中记录所有详细信息,包括状态行、标头和 Cookie,示例:
get("/x").then().log().all()   
  • 在响应中记录只记录状态行、标题或 Cookie,示例:
get("/x").then().log().statusLine()   // 只记录状态行
get("/x").then().log().headers()   // 只记录响应头
get("/x").then().log().cookies()   // 只记录响应 cookies
  • 配置为仅当状态代码与某个值匹配时才记录响应,示例:
get("/x").then().log().ifStatusCodeIsEqualTo(302)   // 仅在状态代码等于 302 时记录日志
get("/x").then().log().ifStatusCodeMatches(matcher)   // 仅在状态代码与提供的配置匹配时才记录日志

只在验证失败时记录日志

  • 从 REST Assured 2.3.1 开始,只有在验证失败时才能记录请求或响应。要记录请求日志,示例:
given().log().ifValidationFails()
  • 要记录响应日志,示例:
then().log().ifValidationFails()
  • 可以使用 LogConfig 同时为请求和响应启用此功能,示例:
given().config(RestAssured.config().logConfig(logConfig()
.enableLoggingOfRequestAndResponseIfValidationFails(HEADERS)))

如果验证失败,日志仅记录请求头。

  • 另外一个快捷方式,用于在验证失败时为所有请求启用请求和响应的日志记录,示例:
RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
  • 从版本 4.5.0 开始,您还可以使用 指定 onFailMessage 测试失败时将显示的消息,示例:
when().
      get().
then().
      onFailMessage("Some specific message").
      statusCode(200);

Header 黑名单配置

从 REST Assured 4.2.0 开始,可以将标头列入黑名单,以便它们不会显示在请求或响应日志中。相反,标头值将替换为 [ BLACKLISTED ] .您可以使用 LogConfig 启用此基于每个标头的功能,示例:

given().config(config().logConfig(logConfig().blacklistHeader("Accept")))  

Filters 过滤器

在 RestAssured 中,你可以使用过滤器来修改请求和响应。过滤器允许你在请求和响应的不同阶段修改请求和响应。例如,你可以在请求之前修改请求,或者在响应之后修改响应。你可以使用过滤器来添加请求头、请求参数、请求体、响应头、响应体等。

过滤器可用于实现自定义身份验证方案、会话管理、日志记录等。若要创建筛选器,需要实现 io.restassured.filter.Filter 接口。要使用过滤器,您可以执行以下操作:

given().filter(new MyFilter())  

REST Assured 提供了几个可供使用的过滤器:

  • io.restassured.filter.log.RequestLoggingFilter :将打印请求规范详细信息的筛选器。
  • io.restassured.filter.log.ResponseLoggingFilter :如果响应与给定状态代码匹配,则将打印响应详细信息的筛选器。
  • io.restassured.filter.log.ErrorLoggingFilter :在发生错误时打印响应正文的筛选器(状态代码介于 400 和 500 之间)。

Ordered Filters 有序过滤器

从 REST Assured 3.0.2 开始,如果需要控制筛选器排序,可以实现 io.restassured.filter.OrderedFilter 接口。在这里,您将实现返回一个整数的方法,getOrder 该整数表示筛选器的优先级。值越低,优先级越高。您可以定义的最高优先级是 Integer.MIN_VALUE,最低优先级是 Integer.MAX_VALUE。未实现 io.restassured.filter.OrderedFilter 的过滤器的默认优先级为 1000。

示例

Response Builder 响应生成器

如果需要更改筛选器中的响应内容,可以使用 ResponseBuilder 基于原始响应创建新的响应。例如,如果要将原始响应的正文更改为其他内容,可以执行以下操作:

Response newResponse = new ResponseBuilder()
.clone(originalResponse).setBody("Something").build();

欢迎关注软件测试同学的公众号“软件测试同学”,原创 QA 技术文章第一时间推送。