Rest-Assure框架使用教程

  • 一、概括:
  • 一、简介:
  • 二、优势
  • 三、 环境准备
  • 二、实战
  • 一、新建一个测试类 TestRestAssured.java
  • 二、接口请求构造
  • 三、接口测试断言
  • 四、json/xml请求
  • 五、json/xml响应断言
  • 六、Headers/Cookie 处理
  • 七、form请求
  • 八、超时处理
  • 九、文件上传测试
  • 十、代理配置
  • 十、认证体系
  • 十一、接口加密与解密
  • 十二、多套环境测试


一、概括:

一、简介:

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

二、优势

  • 简约的接口测试 DSL
  • 支持 xml/json 的结构化解析
  • 支持xpath/jsonpath/gpath解析方式
  • 对 spring 的支持比较全面
  • 符合契约编程思想

三、 环境准备

  • 基于 JDK 11、JUnit5
  • 创建 maven 项目
  • pom.xml 添加 rest-assured 的依赖
<dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>rest-assured</artifactId>
    <version>4.4.0</version>
    <scope>test</scope>
</dependency>

二、实战

一、新建一个测试类 TestRestAssured.java

import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;

public class TestRestAssured {

@Test
void fun(){

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

附录:JUnit5 依赖配置

<!--   JUnit5     -->
<dependency>
    <groupId>org.junit.platform</groupId>
    <artifactId>junit-platform-launcher</artifactId>
    <version>1.5.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.5.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.junit.vintage</groupId>
    <artifactId>junit-vintage-engine</artifactId>
    <version>5.5.2</version>
    <scope>test</scope>
</dependency>

二、接口请求构造

语法格式
given():可以设置测试预设
param():URL 查询参数 when():所要执行的操作
get():GET 请求
post():POST 请求
then():可以解析结果、断言
statusCode():响应状态码断言

  • get请求
import static io.restassured.RestAssured.given;
import org.junit.jupiter.api.Test;

public class TestRestAssuredGet {
    @Test
    void testGet(){
        given()
            // 可以设置测试预设
            .param("username", "Hogwarts")  // 设置查询参数
        .when()
            // 发起 GET 请求
            .get("https://httpbin.ceshiren.com/get")
        .then()
            // 解析结果
            .log().all()  // 打印完整响应信息
            .statusCode(200);  // 响应断言
    }
  • POST 请求
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;

public class TestRestAssuredPost {
    @Test
    void testPost(){
        given()
            // 可以设置测试预设
            .param("username", "Hogwarts")  // 设置查询参数
        .when()
            // 发起 POST 请求
            .post("https://httpbin.ceshiren.com/post")
        .then()
            // 解析结果
            .log().all()  // 打印完整响应信息
            .statusCode(200);  // 响应断言
    }
  • 请求参数

直接拼接在 URL 中
?username=Hogwarts&id=666
GET 请求
param():查询参数
POST 请求
queryParam():查询参数
formParam():表单参数

import static io.restassured.RestAssured.given;
import org.junit.jupiter.api.Test;

public class TestRestAssuredGet {
    @Test
    void testGet(){
        given()
            // 可以设置测试预设
            .param("username", "Hogwarts")  // 设置查询参数
        .when()
            // 发起 GET 请求
            .get("https://httpbin.ceshiren.com/get")
        .then()
            // 解析结果
            .log().all()  // 打印完整响应信息
            .statusCode(200);  // 响应断言

三、接口测试断言

  • 接口断言使用场景

问题: 如何确保请求可以发送成功 如何保证符合业务需求 解决方案: 响应断言

响应结果类型:

类型

断言方法

含义

状态码

statusCode()

响应状态码

响应头

header()

响应头信息

内容

body()

内容完全匹配

  • 简单断言: 响应状态码
import static io.restassured.RestAssured.given;
import org.junit.jupiter.api.Test;

public class TestAssertionStatusCode {
    @Test
    void testStatusCode(){
        given()
        .when()
                .get("https://httpbin.ceshiren.com/get")  // 发起GET请求
        .then()
                .log().all()  // 打印响应结果
                .statusCode(200);  // 响应状态码断言
  • 简单断言: 响应体
import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;
import static org.hamcrest.core.IsEqual.equalTo;

public class TestAssertionBody {
    @Test
    void testBody(){
        given()
        .when()
            .get("https://httpbin.ceshiren.com/get")  // 发起GET请求
        .then()
            .log().all()  // 打印响应结果
            .body("origin", equalTo("113.89.246.184"));  // 响应体断言
    }
}
  • 复杂断言

提问:若碰到复杂断言应该如何处理?

  • jsonpath
  • jsonschema
  • 自行编写解析算法
  • 附录:Hamcrest 依赖配置
<dependency>
  <groupId>org.hamcrest</groupId>
  <artifactId>hamcrest-core</artifactId>
  <version>1.3</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.hamcrest</groupId>
  <artifactId>hamcrest-library</artifactId>
  <version>1.3</version>
  <scope>test</scope>
</dependency>

四、json/xml请求

  • json请求

1、简介

  • 是 JavaScript Object Notation 的缩写
  • 是一种轻量级的数据交换格式
  • 是理想的接口数据交换语言
  • 官网:https://www.json.org/json-en.html

2、json请求

1、构造 JSON 请求体

  • JSON 字符串
  • HashMap 对象 + Jackson库
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;

public class TestJsonStr {
    @Test
    void testJsonRequest(){
        // 定义请求体数据:json序列化后的字符串
        String jsonStr = "{\"Hello2\": \"Hogwarts\"}";

        given()
                .contentType("application/json")  // 设置请求内容类型
                .body(jsonStr)  // 设置请求体数据
                .log().headers()  // 打印请求头信息
                .log().body()  // 打印请求体信息
        .when()
                .post("https://httpbin.ceshiren.com/post")  // 发送请求
        .then()
                .statusCode(200);  // 响应状态码断言
  • 使用 HashMap 对象
import java.util.HashMap;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;

public class TestJsonObj {
    @Test
    void testJsonRequest(){

        // 定义请求体数据:HashMap 对象
        HashMap<String, String> jsonObj = new HashMap<>();
        jsonObj.put("Hello", "Hogwarts");

        given()
                .contentType("application/json")  // 设置请求内容类型
                .body(jsonObj)  // 定制请求体数据
                .log().headers()  // 打印请求头信息
                .log().body()  // 打印请求体信息
        .when()
                .post("https://httpbin.ceshiren.com/post")  // 发送请求
        .then()
                .statusCode(200);  // 响应状态码断言
    }
}

2、XML

简介

  • 是 eXtensible Markup Language 的缩写
  • 是 可扩展标记语言,类似 HTML
  • 是用来传输和存储数据
  • 是通过 < > 标签来描述信息
  • 是 W3C 的推荐标准
<?xml version="1.0"?>
<study>
    <course>
        <name>JUnit5测试框架</name>
        <school>Hogwarts</school>
    </course>

    <course>
        <name>接口自动化测试</name>
        <school>Hogwarts</school>
    </course>
</study>

xml请求

构建 XML 请求体

  • 外部 XML 文件
  • 字符串
  • 示例接口地址:http://dneonline.com/calculator.asmx
  • 外部 XML 文件
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
    <Body>
        <Add xmlns="http://tempuri.org/">
            <intA>1</intA>
            <intB>1</intB>
        </Add>
    </Body>
</Envelope>
  • xml请求
import static io.restassured.RestAssured.*;
import org.junit.jupiter.api.Test;

import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;


public class TestXML {
    @Test
    void testSoapApi() throws IOException {

        // 定义请求体数据:源自文件对象
        File file = new File("src/test/resources/add.xml");
        FileInputStream fis = new FileInputStream(file);
        String reqBody = IOUtils.toString(fis, "UTF-8");

        given()
                .contentType("text/xml")  // 定制请求内容媒体类型
                .body(reqBody)  // 定制请求体数据
                .log().headers()  // 打印请求头信息
                .log().body()  // 打印请求体信息
        .when()
                .post("http://dneonline.com//calculator.asmx")  // 发送请求
        .then()
                .statusCode(200);  // 响应状态码断言
    }
}
  • 附录一:Jackson 依赖配置
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.13.0</version>
  <scope>test</scope>
</dependency>
  • IOUtils 依赖配置
<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>2.11.0</version>
  <scope>test</scope>
</dependency>

五、json/xml响应断言

1、XML 响应断言

  • XPath简介
  • 是 XML 路径语言
  • 是 XML Path Language 的缩写
  • 是用来确定 XML 文档中某部分位置
  • XPath 语法

Xpath

描述

/

根节点

.

现行节点

//

不管位置,选择所有符合条件的元素

*

匹配所有元素节点

[ ]

迭代器标示

|

支持迭代器中做多选

<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
    <Body>
        <Add xmlns="http://tempuri.org/">
            <intA>1</intA>
            <intB>2</intB>
        </Add>
    </Body>
</Envelope>
// 读取解析xml文件并做断言
   @Test
    void readXml() {
        File file = new File("C:\\Users\\86189\\IdeaProjects\\java\\src\\main\\resources\\2.xml");
        FileInputStream is = null;
        try {
            is = new FileInputStream(file);
            String result = IOUtils.toString(is, "UTF-8");
            given().contentType("text/xml").body(result)
                    .when()
                    .post("http://dneonline.com/calculator.asmx")
                    .then()
                    .body("//AddResult.text()",equalTo("3")).log().all();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

2、json响应断言

json简介

  • 是 JavaScript Object Notation 的缩写
  • 是一种轻量级的数据交换格式
  • 是理想的接口数据交换语言
  • 官网:https://www.json.org/json-en.html

json响应数据

{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Accept-Encoding": "gzip,deflate",
    "Hello": "Hogwarts",
    "Host": "httpbin.ceshiren.com",
    "User-Agent": "Apache-HttpClient/4.5.13 (Java/11.0.13)",
    "X-Forwarded-Host": "httpbin.ceshiren.com",
    "X-Scheme": "https"
  },
  "origin": "113.89.246.226",
  "url": "https://httpbin.ceshiren.com/get"
}

jsonpath简介

  • 是一种查询语言
  • 是用来解析 JSON 数据
  • 项目地址:https://github.com/json-path/JsonPath

jsonpath语法

JSONPath

描述

$

根节点

@

现行节点


不管位置,选择所有符合条件的元素

*

匹配所有元素节点

.

取子节点

[]

取子节点,支持名称或者下标

[,]

支持迭代器中做多选

?()

支持过滤操作

语法示例

  • 使用点号
    $.address.city
    $.phoneNumbers[0].number
    $.phoneNumbers[*].number
    $…number
  • 使用中括号
    $[address][city]
    $[phoneNumbers][0][number]
  • 过滤条件
    $.phoneNumbers[?(@.type == ‘iPhone’)].number

JSONPath 响应断言

  • REST assured 内置解析方法
import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;
import static io.restassured.path.json.JsonPath.from;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class TestJSONPathNested {

    @Test
    void fun() {

        // 获取响应信息,并转成字符串对象
        String resp = given()
                .header("Hello", "Hogwarts")
                .when()
                .get("https://httpbin.ceshiren.com/get")
                .then()
                .log().body()
                .extract().response().asString();

        // 使用JSONPath解析响应体
        String word = from(resp).getString("headers.Hello");
        System.out.println(word);

        // 响应断言
        assertEquals("Hogwarts", word);
  • 第三方 json-path解析方法
package ch06;

import com.jayway.jsonpath.JsonPath;
import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class TestJSONPathStandalone {

    @Test
    void fun() {

        // 获取响应信息,并转成字符串对象
        String resp = given()
                .header("Hello", "Hogwarts")
                .when()
                .get("https://httpbin.ceshiren.com/get")
                .then()
                .extract().response().asString();

        // 使用JSONPath解析响应体
        String word = JsonPath.read(resp, "$.headers.Hello");
        System.out.println(word);

        // 响应断言
        assertEquals("Hogwarts", word);

    }
}
  • 附录:JSONPath 依赖配置
<dependency>
    <groupId>com.jayway.jsonpath</groupId>
    <artifactId>json-path</artifactId>
    <version>2.6.0</version>
    <scope>test</scope>
</dependency>

六、Headers/Cookie 处理

1、Headers 简介

  • HTTP Headers 也叫做 HTTP 消息头
  • 允许客户端和服务器传递附加信息
  • 由名称、冒号、具体的值组成
  • 设置请求 Headers
package ch09;

import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;

public class TestHeader {

    @Test
    void testSetHeader() {

        // 配置本地代理,方便监听请求信息
        RestAssured.proxy = host("localhost").withPort(8888);

        given()
                .header("User-Agent", "hogwarts")  // 设置请求头
                .relaxedHTTPSValidation()  // 忽略HTTPS校验
        .when()
                .get("https://httpbin.ceshiren.com/get")  // 发送请求
        .then()
                .log().all()  // 打印完整响应信息
                .statusCode(200);  // 响应断言
    }
}

2、Cookie 简介

添加 Cookie 的两种方式

  • 通过 header() 方法
  • 通过 cookie() 方法
  • 设置请求 Cookie
import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;

public class TestCookieByHeader {

    @Test
    void testAddCookieByHeader() {

        // 配置本地代理,方便监听请求信息
        RestAssured.proxy = host("localhost").withPort(8888);

        // 通过header()方法设置Cookie
        given()
                .header("Cookie", "my_cookie1=hogwarts")  // 设置Cookie
                .relaxedHTTPSValidation()  // 忽略HTTPS校验
        .when()
                .get("https://httpbin.ceshiren.com/get")  // 发送请求
        .then()
                .log().all()  // 打印完整响应信息
                .statusCode(200);  // 响应断言
    }
}
  • 设置请求 Cookie
package ch09;

import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;

public class TestCookie {

    @Test
    void testAddCookie() {

        // 配置本地代理,方便监听请求信息
        RestAssured.proxy = host("localhost").withPort(8888);

        // 添加单个Cookie
        given()
                .cookie("my_cookie", "hogwarts")  // 设置Cookie
                .relaxedHTTPSValidation()  // 忽略HTTPS校验
        .when()
                .get("https://httpbin.ceshiren.com/get")  // 发送请求
        .then()
                .log().all()  // 打印完整响应信息
                .statusCode(200);  // 响应断言
    }
}

七、form请求

1、form 表单请求简介

  • application/x-www-form-urlencoded
    应用场景
  • 数据量不大
  • 数据层级不深的情况
  • 通常以键值对传递
  • form 表单请求的使用
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
import static io.restassured.specification.ProxySpecification.host;

public class TestFormParam {

    @Test
    void testFormParam() {

        // 配置本地代理,方便监听请求信息
        RestAssured.proxy = host("localhost").withPort(8888);
        // 忽略HTTPS校验
        RestAssured.useRelaxedHTTPSValidation();

        // 发送 POST 请求
        given()
                .formParam("username", "hogwarts")  // 添加表单数据
                .log().headers()  // 打印请求头信息
                .log().body()  // 打印请求体信息
        .when()
                .post("https://httpbin.ceshiren.com/post")  // 发送请求
        .then()
                .statusCode(200);  // 响应断言
    }
}
// 调用 formParams() 方法
public class TestFormParams {

    @Test
    void testFormParams() {

        // 配置本地代理,方便监听请求信息
        RestAssured.proxy = host("localhost").withPort(8888);
        // 忽略HTTPS校验
        RestAssured.useRelaxedHTTPSValidation();

        // 发送 POST 请求
        given()
                .formParams("username", "hogwarts",
                 "pwd", "666")  // 添加表单数据
                .log().headers()
                .log().body()
        .when()
                .post("https://httpbin.ceshiren.com/post")  // 发送请求
        .then()
                .statusCode(200);  // 响应断言
    }
}

八、超时处理

  • 1、为什么需要请求超时处理
  • 设置请求超时的效果
  • 设置超时时间:超时后会停下来,然后报错
import io.restassured.RestAssured;
import io.restassured.config.HttpClientConfig;
import io.restassured.config.RestAssuredConfig;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;


public class TestTimeout {

    @BeforeAll
    static void setupClass(){
        RestAssured.baseURI = "https://httpbin.ceshiren.com";
    }
    
    @Test
    void case1() {
        given()
        .when()
                .get("/get")  // 发送GET请求
        .then()
                .statusCode(200);  // 响应断言
    }

    @Test
    void case2(){
        // 自定义HttpClientConfig对象
        // 设置响应超时时长为3秒,单位是毫秒
        HttpClientConfig clientConfig = HttpClientConfig
                .httpClientConfig()
                .setParam("http.socket.timeout", 3000);
        // 定义RestAssuredConfig对象
        // 传入自定义的HttpClientConfig对象
        RestAssuredConfig myTimeout = RestAssuredConfig
                .config()
                .httpClient(clientConfig);

        // 接口调用
        given()
                .config(myTimeout)  // 设置超时处理
        .when()
                .get("/delay/10")  // 特定接口,延迟10秒响应
        .then()
                .statusCode(200);  // 响应断言
    }

    @Test
    void case3(){
        given()
        .when()
                .get("/get")  // 发送GET请求
        .then()
                .statusCode(200);  // 响应断言
    }

}

九、文件上传测试

1、文件上传接口场景

  • Content-Type 类型:multipart/form-data
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import java.io.File;
import static io.restassured.RestAssured.given;
import static io.restassured.specification.ProxySpecification.host;

public class TestMultiPart {
/**
1,创建本地文件
hogwarts.txt
2,调用方法
multiPart()
参数:String name
参数:File file
*/
    @Test
    void testUploadFile(){

        // 需要上传的文件对象
        File myFile = new File("src/test/resources/hogwarts.txt");

        // 定义一个代理的配置信息
        RestAssured.proxy = host("localhost").withPort(8888);
        // 忽略HTTPS校验
        RestAssured.useRelaxedHTTPSValidation();

        given()
            .multiPart("hogwarts", myFile)  // 传递文件对象
            .log().headers()  // 打印请求消息头
            .log().body()  // 打印请求消息体
        .when()
            .post("https://httpbin.ceshiren.com/post")  //发送POST请求
        .then()
            .statusCode(200);  // 响应断言
    }
}
  • 携带多种数据
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import java.io.File;
import static io.restassured.RestAssured.given;
import static io.restassured.specification.ProxySpecification.host;

public class TestMultiParts {

    @Test
    void testUploadFiles(){

        // 需要上传的文件对象
        File myFile = new File("src/test/resources/hogwarts.txt");

        // 定义一个代理的配置信息
        RestAssured.proxy = host("localhost").withPort(8888);
        // 忽略HTTPS校验
        RestAssured.useRelaxedHTTPSValidation();

        given()
            .multiPart("hogwarts", myFile)  // 传递文件对象
            .multiPart("ceshiren", "{\"hogwarts\": 666}",
             "application/json")  // 传递JSON数据
            .log().headers()  // 打印请求消息头
            .log().body()  // 打印请求消息体
        .when()
            .post("https://httpbin.ceshiren.com/post")  // 发送POST请求
        .then()
            .statusCode(200);  // 响应断言
    }
}

十、代理配置

1、代理简介

  • 介于客户端与服务器之间
  • 可以监听请求和响应信息
  • 充当防火墙和 Web 过滤器

2、代理前后对比

java sendRedirect 参数说明_自动化测试


java sendRedirect 参数说明_接口自动化_02


3、代理与接口测试

  • 更直观的排查请求错误
  • 获取正确的的接口请求与响应信息
  • 开启代理工具监听请求
  • 获取自动化测试的请求与响应信息
  • 对比两次请求响应的区别

    4、REST assured 使用代理
  • 开启代理工具监听请求
  • 配置代理
    局部:通过 proxy() 方法
    全局:定义 proxy 对象

5、使用代理请求 HTTP

import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;
import static io.restassured.specification.ProxySpecification.host;

public class TestHttpProxyConf {

    @Test
    void testHTTPProxy() {

        // 定义一个代理的配置信息(也可以直接添加proxy参数)
        given()
                .proxy("localhost",8888)  // 设置代理
             //   .proxy("127.0.0.1",8889)  // 代理的3种写法
        .when()
                .get("http://httpbin.org/get")  // 发送 HTTP请求
        .then()
                .log().all()  // 打印完整响应信息
                .statusCode(200);  // 响应断言
    }
}

- 使用代理请求 HTTPS

import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;
import static io.restassured.specification.ProxySpecification.host;


public class TestHttpsProxyConf {

    @Test
    void testHTTPProxy() {

        // 定义一个代理的配置信息
        RestAssured.proxy = host("localhost").withPort(8888);

        given()
                .relaxedHTTPSValidation()  // 忽略HTTPS校验
        .when()
                .get("https://httpbin.ceshiren.com/get")
        .then()
                .log().all()  // 打印完整响应信息
                .statusCode(200);  // 响应断言
    }
}

十、认证体系

1、认证体系简介

  • 是验证通信发送者的数字身份的过程
  • REST-assured 认证方案
    OAuth
    digest
    certificate 证书认证
    form 表单认证
    basic authentication 基本认证

java sendRedirect 参数说明_测试框架_03


- 使用基本认证

import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
import static io.restassured.specification.ProxySpecification.host;
/**
操作步骤:
- 开启本地代理
- 编写接口测试用例
- 执行测试用例
*/
public class TestAuth {

    @Test
    void testAuth(){

        // 定义一个代理的配置信息
        RestAssured.proxy = host("localhost").withPort(8888);

        // 忽略HTTPS校验
        RestAssured.useRelaxedHTTPSValidation();

        // 被测接口地址
        String testURL = "https://httpbin.ceshiren.com/basic-auth/hogwarts/666";

        given()
                .auth().basic("hogwarts", "666")  // 设置基本认证
        .when()
                .get(testURL)  // 发送GET请求
        .then()
                .statusCode(200);  // 响应断言
    }
}

十一、接口加密与解密

1、加密解密简介

  • 加密:明文转换成密文的过程
  • 解密:密文还原成明文的过程
  • 常见加密算法
    AES
    RSA
    MD5
    Base64

2、解密方案

  • 通用加密算法:使用对应解密算法
  • 自研加密算法:研发提供加解密 lib
  • 第三方加密服务:寻求加密方提供远程解析服务

3、接口解密实战

import org.apache.commons.codec.binary.Base64;
import org.junit.jupiter.api.Test;

import java.nio.charset.StandardCharsets;


public class TestBase64 {
    @Test
    void testEncodeAndDecode(){

        // 加密一串数据:hogwarts
        // 获取字节数组
        byte[] arr1 = "hogwarts".getBytes(StandardCharsets.UTF_8);
        // 执行加密
        String encodedMsg = Base64.encodeBase64String(arr1);


        // 解密一串数据:aG9nd2FydHM=
        // 执行解密
        byte[] arr2 = Base64.decodeBase64("aG9nd2FydHM=");
        // 生成字符串
        String decodeMsg = new String(arr2, StandardCharsets.UTF_8);


    }
}

- 解密后响应断言

import org.apache.commons.codec.binary.Base64;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import static io.restassured.RestAssured.given;

public class TestDecode {
    @Test
    void testDecode(){

        // 加密一串数据
        byte[] data = "hogwarts".getBytes(StandardCharsets.UTF_8);
        String secretMsg = Base64.encodeBase64String(data);

        // 发起请求,并获取响应信息
        LinkedHashMap<String, String> responseForm =
            given()
                .formParam("msg", secretMsg)  // 提交表单数据
            .when()
                .post("https://httpbin.ceshiren.com/post")  // 发起POST请求
            .then()
                .log().all()  // 打印完整响应信息
                .extract().path("form");  // 提取form信息

        // 提取加密字段
        String encodedMsg = responseForm.get("msg");

        // 解密操作
        String decodedMsg = new String(Base64.decodeBase64(encodedMsg));
        // 响应断言
        Assertions.assertEquals("hogwarts", decodedMsg);
    }
}

十二、多套环境测试

1、多套环境测试背景

  • 集成测试环境
  • 验收测试环境
  • 灰度测试环境

2、多套环境测试解决方案

  • 测试环境 1
    域名:http://httpbin.org
    接口:/get
  • 测试环境 2
    域名:https://httpbin.ceshiren.com
    接口:/get

3、解决方案:

import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
/**
多套环境测试方案(一)
痛点
- 硬编码耦合
- 维护成本高
 */
public class TestEnv {
    @Test
    void testOrg(){
        // 测试org环境接口
        given()
        .when()
            .get("http://httpbin.org/get")  // 发送GET请求
        .then()
            .statusCode(200);
    }

    @Test
    void testCeshiren(){
        // 测试ceshiren环境接口
        given()
        .when()
            .get("https://httpbin.ceshiren.com/get")  // 发送GET请求
        .then()
            .statusCode(200);
    }
}
/**
多套环境测试方案(二)
优点
通过配置信息管理环境
痛点
多个测试文件维护成本高
*/
import io.restassured.RestAssured;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import static io.restassured.RestAssured.given;

public class TestEnvConf {

    @BeforeAll
    static void setupClass(){
        // 实例化环境配置对象
        HashMap<String, String> envs = new HashMap<>();
        // 测试环境1的域名配置
        envs.put("org", "http://httpbin.org/get");
        // 测试环境1的域名配置
        envs.put("ceshiren", "http://httpbin.ceshiren.com/get");

        // 选定默认环境名称,方便灵活切换
        envs.put("default", "org");

        // 设置基路径,值为选定的域名地址
        RestAssured.baseURI = envs.get(envs.get("default"));
    }

    @Test
    void testEnvs(){
        given()
        .when()
            .get("/get")  // 发送GET请求
        .then();
    }

}
/**
多套环境测试方案(三)
最佳实践:配置文件
*/
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import io.restassured.RestAssured;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import static io.restassured.RestAssured.given;

public class TestEnvYaml {

    @BeforeAll
    static void setupClass() throws IOException {
        /*
        使用Jackson读取yaml文件
         */

        // 实例化一个ObjectMapper 对象
        ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
        // 读取 resources 目录中的envs.yaml文件
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        File yamlFile = new File(classLoader.getResource("envs.yaml").getFile());
        // 定义序列化的结构 TypeReference
        TypeReference<HashMap<String, String>> typeRef = new
                  TypeReference<HashMap<String, String>>() {};
        // 解析envs.yaml文件内容
        HashMap<String, String> envs = objectMapper.readValue(yamlFile, typeRef);
        // 设置基路径,值为选定的域名地址
        RestAssured.baseURI = envs.get(envs.get("default"));
    }

    @Test
    void testEnvs() {

        //发起请求
        given()
        .when()
                .get("/get")
        .then()
                .statusCode(200);
    }
}