REST-Assured介绍和使用(2)

接口请求体(文件)

文件上传接口场景

  • Content-Type 类型
    • multipart/form-data
  • 上传文件
    • 创建本地文件
      • hogwarts.txt
    • 调用方法
      • multiPart()
        • 参数:String name
        • 参数:File file
@Test
void header(){
    // 需要上传的文件对象
    File myFile = new File("src/test/resources/hogwarts.txt");

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

    given()
            .multiPart("hogwarts", myFile)  // 传递文件对象
            .log().all()
    .when()
            .post("https://httpbin.ceshiren.com/post")  //发送POST请求
    .then()
            .log().all()
            .statusCode(200);  // 响应断言
}

image

  • 携带多种数据
@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);  // 响应断言
}

image

接口请求体(from表单)

  • Content-Type 类型
    • application/x-www-form-urlencoded
  • 应用场景
    • 数据量不大
    • 数据层级不深的情况
    • 通常以键值对传递
  • form表单请求的使用
    • 调用 formParam() 方法
@Test
void testFormParam() {
    // 忽略HTTPS校验
    RestAssured.useRelaxedHTTPSValidation();

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

image

  • 调用 formParams() 方法
@Test
void testFormParams() {
    // 忽略HTTPS校验
    RestAssured.useRelaxedHTTPSValidation();

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

image

接口请求体(XML)

  • 简介
    • 是 eXtensible Markup Language 的缩写
    • 是 可扩展标记语言,类似 HTML
    • 是用来传输和存储数据
    • 是通过 < > 标签来描述信息
    • 是 W3C 的推荐标准
  • 请求
    • 构建XML请求体
      • 外部XML文件
        • 导入POM
<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>2.11.0</version>
  <scope>test</scope>
</dependency>
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
    <Body>
        <Add xmlns="http://tempuri.org/">
            <intA>1</intA>
            <intB>1</intB>
        </Add>
    </Body>
</Envelope>
@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()
            .log().all()
            .statusCode(200);  // 响应状态码断言
}
  • 字符串

接口响应断言(XML)

  • XPath 基本语法
    • 简介
      • 是 XML 路径语言
      • 是 XML Path Language 的缩写
      • 是用来确定 XML 文档中某部分位置
    • 语法
Xpath 描述
/ 根节点
. 现行节点
// 不管位置,选择所有符合条件的元素
* 匹配所有元素节点
迭代器标示
| 支持迭代器中做多选
  • XML 响应结果断言
@Test
void testXML() 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)  // 定制请求体数据
    .when()
            .post("http://dneonline.com/calculator.asmx")  // 发送请求
    .then()
            .log().body()  // 打印响应体信息
            .body("//AddResult.text()", equalTo("2"));  // 响应断言

}

cookie处理

  • HTTP Headers
    • 简介
      • HTTP Headers 也叫做 HTTP 消息头
      • 允许客户端和服务器传递附加信息
      • 由名称、冒号、具体的值组成
    • 设置请求Headers
@Test
void testSetHeader() {

    given()
            .header("User-Agent", "hogwarts")  // 设置请求头
            .relaxedHTTPSValidation()  // 忽略HTTPS校验
    .when()
            .get("https://httpbin.ceshiren.com/get")  // 发送请求
    .then()
            .log().all()  // 打印完整响应信息
            .statusCode(200);  // 响应断言
}
  • HTTP Cookie
    • Cookie 使用场景
    • 添加 Cookie 的两种方式
      • 通过 header() 方法
@Test
void testAddCookieByHeader() {

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

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

超时处理

  • 为什么需要请求超时处理

image

  • 设置请求超时的效果

image

  • 设置超时时间
    • 步骤
      • 创建 HttpClientConfig 实例
      • 创建 RestAssuredConfig 实例
      • given 语句中调用 config() 方法
public class RestAssuredTest {
@BeforeAll
static void setupClass(){
    RestAssured.baseURI = "https://httpbin.ceshiren.com";
    // 忽略HTTPS校验
    RestAssured.useRelaxedHTTPSValidation();
}

@Test
void case1() {
    given()
            .when()
            .get("/get")  // 发送GET请求
            .then()
            .statusCode(200);  // 响应断言
}
@Test
void case2(){
    // 自定义HttpClientConfig对象
    // 设置响应超时时长为3秒,单位是毫秒
    HttpClientConfig clientConfig = HttpClientConfig
            .httpClientConfig()
            .setParam("https.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);  // 响应断言
}
}

代理配置

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

image

  • 代理后

image

  - RESTassured使用代理
     - 开启代理工具监听请求
     - 配置代理
        - 局部:通过proxy()方法
@Test
void testHTTPProxy() {
    given()
            .proxy(8888)  // 设置代理
    .when()
            .get("http://httpbin.org/get")  // 发送 HTTP请求
    .then()
            .log().all()  // 打印完整响应信息
            .statusCode(200);  // 响应断言
}
  • 全局:定义proxy对象
@Test
void testHTTPProxy1() {
    // 定义一个代理的配置信息
    RestAssured.proxy = host("localhost").withPort(8888);

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

多层嵌套响应断言

  • 多层嵌套响应介绍

多层嵌套结构

// - 层级多。
// - 嵌套关系复杂。
{
  "errcode": 0,
  "errmsg": "ok",
  "userid": "zhangsan",
  "name": "张三",
  "department": [1, 2],
  "order": [1, 2],
  "position": "后台工程师",
  "mobile": "13800000000",
  "gender": "1",
  "email": "zhangsan@gzdev.com",
  "biz_mail": "zhangsan@qyycs2.wecom.work",
  "is_leader_in_dept": [1, 0],
  "direct_leader": ["lisi", "wangwu"],
  "avatar": "http://wx.qlogo.cn/mmopen/ajNVdqHZLLA3WJ6DSZUfiakYe37PKnQhBIeOQBO4czqrnZDS79FH5Wm5m4X69TBicnHFlhiafvDwklOpZeXYQQ2icg/0",
  "thumb_avatar": "http://wx.qlogo.cn/mmopen/ajNVdqHZLLA3WJ6DSZUfiakYe37PKnQhBIeOQBO4czqrnZDS79FH5Wm5m4X69TBicnHFlhiafvDwklOpZeXYQQ2icg/100",
  "telephone": "020-123456",
  "alias": "jackzhang",
  "address": "广州市海珠区新港中路",
  "open_userid": "xxxxxx",
  "main_department": 1,
  "extattr": {
    "attrs": [
      {
        "type": 0,
        "name": "文本名称",
        "text": {
          "value": "文本"
        }
      },
      {
        "type": 1,
        "name": "网页名称",
        "web": {
          "url": "http://www.test.com",
          "title": "标题"
        }
      }
    ]
  },
  "status": 1,
  "qr_code": "https://open.work.weixin.qq.com/wwopen/userQRCode?vcode=xxx",
  "external_position": "产品经理",
  "external_profile": {
    "external_corp_name": "企业简称",
    "wechat_channels": {
      "nickname": "视频号名称",
      "status": 1
    },
    "external_attr": [
      {
        "type": 0,
        "name": "文本名称",
        "text": {
          "value": "文本"
        }
      },
      {
        "type": 1,
        "name": "网页名称",
        "web": {
          "url": "http://www.test.com",
          "title": "标题"
        }
      },
      {
        "type": 2,
        "name": "测试app",
        "miniprogram": {
          "appid": "wx8bd80126147dFAKE",
          "pagepath": "/index",
          "title": "my miniprogram"
        }
      }
    ]
  }
}
  • JSONPath
    • 简介
      • 在 JSON 数据中定位和提取特定信息的查询语言。
      • JSONPath 使用类似于 XPath 的语法,使用路径表达式从 JSON 数据中选择和提取数据。
      • 相比于传统的提取方式,更加灵活,并且支持定制化。
    • 对比
场景 对应实现 JSONPath实现
提取 errcode 对应的值 res[“errcode”] $.errcode
提取 title 对应的值 res[“extattr”][“external_profile”][“external_attr”][1][“web”][“title”] 等 $…title
提取 type 为 0 的 name 编码实现 $…external_attr[?(@.type==0)].name
提取 attrs 下的所有的 name 编码实现 $…attrs…name
  • 语法
符号 描述
$ 查询的根节点对象,用于表示一个 json 数据,可以是数组或对象
@ 过滤器(filter predicate)处理的当前节点对象
* 通配符
. 获取子节点
递归搜索,筛选所有符合条件的节点
?() 过滤器表达式,筛选操作
[start:end] 数组片段,区间为[start,end),不包含 end
[A]或[A,B] 迭代器下标,表示一个或多个数组下标
<!-- 相关依赖 -->
<properties>
    <json-path.version>2.8.0</json-path.version>
</properties>
<dependency>
      <groupId>com.jayway.jsonpath</groupId>
      <artifactId>json-path</artifactId>
      <version>${json-path.version}</version>
  </dependency>
@Test
void jsonpathRes(){
    String jsonData = "{\"username\":\"hogwarts\",\"password\":\"test12345\",\"code\":\"\"}";
    String res = given()
            .body(jsonData)
            .when()
            .post("https://httpbin.hogwarts.ceshiren.com/post")
            .then()
            .extract().response().getBody().asString();
    // 第一种获取方式
    DocumentContext context = JsonPath.parse(res);
    ArrayList<String> codeList = context.read("$..code");
    // 第二种获取方式
    // ArrayList<String> codeList2 = JsonPath.read(res, "$..code");
}