一、简介:
二、优势
三、 环境准备
io.rest-assured
rest-assured
4.4.0
test
一、新建一个测试类 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():响应状态码断言
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); // 响应断言
}
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请求
1、简介
是 JavaScript Object Notation 的缩写
是一种轻量级的数据交换格式
是理想的接口数据交换语言
官网:https://www.json.org/json-en.html
2、json请求
1、构造 JSON 请求体
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); // 响应状态码断言
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
简介
<study>
<course>
<name>JUnit5测试框架name>
<school>Hogwartsschool>
course>
<course>
<name>接口自动化测试name>
<school>Hogwartsschool>
course>
study>
xml请求
构建 XML 请求体
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Body>
<Add xmlns="http://tempuri.org/">
<intA>1intA>
<intB>1intB>
Add>
Body>
Envelope>
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); // 响应状态码断言
}
}
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.0</version>
<scope>test</scope>
</dependency>
<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简介
jsonpath语法
JSONPath | 描述 |
---|---|
$ | 根节点 |
@ | 现行节点 |
… | 不管位置,选择所有符合条件的元素 |
* | 匹配所有元素节点 |
. | 取子节点 |
[] | 取子节点,支持名称或者下标 |
[,] | 支持迭代器中做多选 |
?() | 支持过滤操作 |
语法示例
JSONPath 响应断言
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);
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);
}
}
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.6.0</version>
<scope>test</scope>
</dependency>
六、Headers/Cookie 处理
1、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 的两种方式
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); // 响应断言
}
}
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 表单请求简介
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); // 响应断言
}
}
八、超时处理
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、文件上传接口场景
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、代理简介
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() {
// 定义一个代理的配置信息
RestAssured.proxy = host("localhost").withPort(8888);
given()
.proxy(8888) // 设置代理
.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、认证体系简介
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、加密解密简介
2、解密方案
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、多套环境测试解决方案
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);
}
}