02:REST-Assured介绍和使用

介绍

REST-assured是由Java实现的REST API测试框架,支持发起POST , GET , PUT , ,DELETE等请求,可以用来验证和校对响应信息。其官网地址为:http://rest-assured.io/

优势

  • 简约的接口测试DSL
  • 支持多种数据格式:支持 xml/json 的结构化解析。
  • 内置断言库:支持 xpath/jsonpath/gpath 解析方式。
  • 可与多种测试框架集成:支持与 JUnit、TestNG 等测试框架集成。
  • 对Spring的支持比较全面
  • 符合契约编程思想

环境准备

POM文件添加REST-assured的依赖

<!-- rest-assured 相关依赖 -->
<properties>
    <rest-assured.version>5.3.0</rest-assured.version>
	<json-path.version>2.8.0</json-path.version>
</properties>

<dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>rest-assured</artifactId>
    <version>${rest-assured.version}</version>
    <scope>compile</scope>
</dependency>
<!-- json path 解析json文件 -->
<dependency>
    <groupId>com.jayway.jsonpath</groupId>
    <artifactId>json-path</artifactId>
    <version>${json-path.version}</version>
</dependency>

接口请求构造

  • 语法格式
given()
    // given 设置测试预设
    .header("Hello", "Hogwarts")
.when()
    // when 所要执行的请求动作
    .get("https://httpbin.ceshiren.com/get")
.then()
    // then 解析结果、断言
    .log().all();  // 打印全部响应信息(响应头、响应体、状态等等)
  • 准备数据:given()

    • 打印请求全部日志:log().all()
    • URL请求参数:queryParam()
    • 设置 Content-Type:contentType()
    • 添加 header:headers()
    • 添加cookie:cookie()
    • 请求体:body()
    • 其他:…
  • 发送请求:when()

    • get请求:get()。
    • post请求:post()。
    • put请求::put()。
    • delete请求:delete()。
  • 验证返回结果then()

    • 打印全部日志:log().all()
    • 验证响应:body()
    • 验证响应状态码:statusCode()
    • 其他:…

image

  • 接口请求

    • GET请求
@Test
public void testGET(){
  given()
          .relaxedHTTPSValidation()
  .when()
          .get("https://httpbin.ceshiren.com/get")
  .then()
          .log()
          .all();
}
  • POST请求
@Test
public void testPost(){
    given()
            .relaxedHTTPSValidation()
    .when()
            .post("https://httpbin.ceshiren.com/post")
    .then()
            .log()
            .all();
}
  • PUT请求
@Test
public void testPut(){
    given()
            .relaxedHTTPSValidation()
    .when()
            .put("https://httpbin.ceshiren.com/put")
    .then()
            .log()
            .all();
}
  • DELETE请求
@Test
public void testPatch(){
    given()
            .relaxedHTTPSValidation()
    .when()
            .patch("https://httpbin.ceshiren.com/patch")
    .then()
            .log()
            .all();
}
  • 请求参数

    • 应用场景

      • 条件查询接口
      • 鉴权接口
      • 其他接口(具体依据接口文档)
    • 请求参数的方式

      • 直接拼接在URL中
@Test
void getURLReq(){
    given()
            .relaxedHTTPSValidation().
    when()
            .get("https://httpbin.ceshiren.com/get?name=ad&scholl=hogwarts")
    .then()
            .log().all();
}
  • 通过given的queryParam()传递

  • queryParam():单个URL参数。

@Test
void getParamReq() {
    given()
            .relaxedHTTPSValidation()
            .queryParam("name", "wt")
            .queryParam("scholl", "hogwarts")
    .when()
            .get("https://httpbin.ceshiren.com/get")
    .then()
            .log().all();
}
  • queryParams():多个URL参数
@Test
void getParamsReq() {
    HashMap<String, String> params = new HashMap<>();
    params.put("name", "wt");
    params.put("scholl", "hogwarts");

    given()
            .relaxedHTTPSValidation()
            .queryParams(params)
    .when()
            .get("https://httpbin.ceshiren.com/get")
    .then()
            .log().all();
}
  • 请求体信息

    • 什么是请求头

HTTP 请求头是在 HTTP 请求消息中包含的元数据信息,用于描述请求或响应的一些属性和特征。在实际工作中具体要关注的头信息字段需要和研发沟通

常见的头信息

内容 含义
Authorization 表示客户端请求的身份验证信息
Cookie 表示客户端的状态信息,通常用于身份验证和会话管理
Content-Type 表示请求消息体的 MIME 类型
User-Agent 发送请求的客户端软件信息
其他(根据接口文档设计要求决定其作用)
  • 应用场景

    • 身份认证
    • 指定请求数据类型
  • 接口请求体构造

    • 直接使用参数
@Test
void header(){
    given()
            .relaxedHTTPSValidation()
            .headers("Authorization", "verifyMessage")
            .headers("name", "wt")
            .log().all()
    .when()
            .get("https://httpbin.ceshiren.com/get")
    .then()
            .log().all();
}
  • 使用HashMap
@Test
void headerMap(){
    HashMap<String, String> headerMap = new HashMap<>();
    headerMap.put("Authorization", "verifyMessage");
    headerMap.put("name", "wt");
    headerMap.put("school", "hogwarts");

    given()
            .relaxedHTTPSValidation()
            .headers(headerMap)
            .log().all()
    .when()
            .get("https://httpbin.ceshiren.com/get")
    .then()
            .log().all();
}
  • 常用的接口请求体应用场景
类型 介绍 Content-type
JSON
(JavaScript Object Notation) 轻量级的数据交换格式,最常见的一种类型。 application/json
表单数据
(Form Data) 以键值对的形式提交数据,例如通过 HTML 表单提交数据。 application/x-www-form-urlencoded
XML
(eXtensible Markup Language) 常用的标记语言,通常用于传递配置文件等数据。 application/xml
text/xml
文件
(File) 可以通过请求体上传文件数据,例如上传图片、视频等文件。 上传文件的 MIME 类型,例如 image/jpeg
multipart/form-data
纯文本
(Text) 纯文本数据,例如发送邮件、发送短信等场景 text/plain
其他格式 二进制数据、protobuf 等格式
  • Json格式请求体

通过given().body(jsonData)添加请求体信息:

@Test
void objectPostJson(){
    JSONObject requestBody = new JSONObject();
    requestBody.put("key1", "value1");
    requestBody.put("key2", "value2");

    given()
            .relaxedHTTPSValidation()
            .body(requestBody.toString())
            .log().all()
    .when()
            .post("https://httpbin.ceshiren.com/post")
    .then().log().all();
}
@Test
void stringPostJson(){
    String jsonData = "{\"username\":\"hogwarts\",\"password\":\"test12345\",\"code\":\"\"}";

    given()
            .relaxedHTTPSValidation()
            .body(jsonData)
            .log().all()
    .when()
            .post("https://litemall.hogwarts.ceshiren.com/admin/auth/login")
    .then()
            .log().all();
}

接口断言

  • 接口响应断言

    • 验证响应状态码。
    • 验证响应体返回字段信息是否符合业务需求。
    • 验证响应体字段的数据类型、数据格式。
  • 为什么需要接口断言

    • 确保接口返回的数据符合预期。
    • 检测接口是否正常运行。
    • 验证响应体返回字段信息是否符合预期的业务需求
    • 验证响应体字段的数据类型、数据格式。
    • 提高测试效率。
  • 响应断言方式

类型 断言方法
状态码 then.statusCode()
响应头 then.header()
内容 then.body()
  • 响应状态码断言
@Test
void objectPostJson(){

    given()
            .relaxedHTTPSValidation()
            .log().all()
    .when()
            .post("https://httpbin.ceshiren.com/post")
    .then()
            .statusCode(200)
            .log().all();
}
  • Json响应断言

    • 直接断言: then().body()

      • 结合 hamcrest 使用(hamcrest使用)
      • body(“想要提取的信息”, 预期结果操作)。
      • 使用 gpath 语法提取(了解 gpath语法)
// 断言是否相等
@Test
void jsonBody(){
    given()
            .relaxedHTTPSValidation()
    .when()
            .get("https://httpbin.hogwarts.ceshiren.com/get")  // 发起GET请求
    .then()
            .body("url",equalTo("https://httpbin.hogwarts.ceshiren.com/get"))
            // 结合hamcrest响应体断言
            .log().all();// 打印响应结果
}

// 断言元素是否包含。
@Test
void extractArray(){
    String jsonData = "{\"username\":\"hogwarts\",\"password\":\"test12345\",\"code\":[1,2,3]}";
    given()
            .body(jsonData)
    .when()
            .post("https://httpbin.hogwarts.ceshiren.com/post")
    .then()
            .body("json.code", hasItem(2))
            .log().all();
}
  • 提取后断言: then().extract().path()
    • extract(): 提取方法,返回值为Response。
    • path(): 从返回值中提取想要的信息(使用 gpath 语法)。
// 响应嵌套提取。
@Test
void extractJson(){
    String jsonData = "{\"username\":\"hogwarts\",\"password\":\"test12345\",\"code\":[1,2,3]}";
    ArrayList data =
            given()
                    .body(jsonData)
            .when()
                    .post("https://httpbin.hogwarts.ceshiren.com/post")
            .then()
                    .log().all()
                    .extract().path("json.code");

    System.out.println(data);
}

// 提取数组中的元素。
@Test
void extractArray(){
    String jsonData = "{\"username\":\"hogwarts\",\"password\":\"test12345\",\"code\":[1,2,3]}";

    Integer data =
            given()
                .body(jsonData)
            .when()
                .post("https://httpbin.hogwarts.ceshiren.com/post")
            .then()
                .log().all()
                .extract().path("json.code[1]");
    System.out.println(data);
}
  • 复杂断言
    • jsonpath
    • jsonschema
    • 自行编写解析算法

问题

  • 遇到报错"javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target"

原因:网站使用了无效的SSL证书

解决:使用relaxedHTTPSValidation

    @Test
    void header(){
        given()
                .relaxedHTTPSValidation()
        .when()
                .get("https://httpbin.ceshiren.com/get")
        .then()
                .log().all();
    }

后记

POM完整依赖配置

<!-- 其他使用到的依赖配置  -->
<!--   版本配置-->
<properties>
    <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
    <java.version>11</java.version>
    <junit.jupiter.version>5.9.2</junit.jupiter.version>
    <maven.compiler.version>3.11.0</maven.compiler.version>
    <maven-surefire-plugin.version>3.0.0</maven-surefire-plugin.version>
    <rest-assured.version>5.3.0</rest-assured.version>
    <json-path.version>2.8.0</json-path.version>
    <!-- allure报告 -->
    <allure.version>2.21.0</allure.version>
    <aspectj.version>1.9.19</aspectj.version>
    <allure.maven.version>2.12.0</allure.maven.version>
    <allure.cmd.download.url>
        https://repo.maven.apache.org/maven2/io/qameta/allure/allure-commandline
    </allure.cmd.download.url>
</properties>
<dependencyManagement>
    <!--        junit5 版本管理, 找到对应依赖关系的 pom 文件,为了解决依赖冲突问题-->
    <dependencies>
        <dependency>
            <groupId>org.junit</groupId>
            <artifactId>junit-bom</artifactId>
            <version>${junit.jupiter.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>

    <!--        junit 相关依赖下载-->
    <!-- junit5 -->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <scope>test</scope>
    </dependency>
    <!-- junit5-suite -->
    <dependency>
        <groupId>org.junit.platform</groupId>
        <artifactId>junit-platform-suite</artifactId>
        <scope>test</scope>
    </dependency>
    <!-- 用做兼容老版本 -->
    <dependency>
        <groupId>org.junit.vintage</groupId>
        <artifactId>junit-vintage-engine</artifactId>
        <scope>test</scope>
    </dependency>
    <!-- rest-assured -->
    <dependency>
        <groupId>io.rest-assured</groupId>
        <artifactId>rest-assured</artifactId>
        <version>${rest-assured.version}</version>
        <scope>compile</scope>
    </dependency>
    <!-- json path 解析json文件 -->
    <dependency>
        <groupId>com.jayway.jsonpath</groupId>
        <artifactId>json-path</artifactId>
        <version>${json-path.version}</version>
    </dependency>
    <!--        allure报告-->
    <dependency>
        <groupId>io.qameta.allure</groupId>
        <artifactId>allure-junit5</artifactId>
        <version>${allure.version}</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>${aspectj.version}</version>
    </dependency>

</dependencies>
<build>
    <plugins>
        <!--            maven 命令行执行插件-->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>${maven-surefire-plugin.version}</version>
            <configuration>
                <argLine>
                    -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
                </argLine>
            </configuration>
            <!--                防止maven与junit5使用依赖冲突的问题-->
            <dependencies>
                <dependency>
                    <groupId>org.junit.jupiter</groupId>
                    <artifactId>junit-jupiter-engine</artifactId>
                    <version>${junit.jupiter.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                    <version>${junit.jupiter.version}</version>
                </dependency>
            </dependencies>
        </plugin>
        <!--            maven 编译使用插件-->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>${maven.compiler.version}</version>
            <configuration>
                <parameters>true</parameters>
                <source>${java.version}</source>
                <target>${java.version}</target>
                <encoding>${maven.compiler.encoding}</encoding>
            </configuration>
        </plugin>

        <plugin>
            <groupId>io.qameta.allure</groupId>
            <artifactId>allure-maven</artifactId>
            <version>${allure.maven.version}</version>
            <configuration>
                <reportVersion>${allure.version}</reportVersion>
                <allureDownloadUrl>${allure.cmd.download.url}/${allure.version}/allure-commandline-${allure.version}.zip</allureDownloadUrl>
            </configuration>
        </plugin>
    </plugins>
</build>