介绍
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()
- 其他:…
-
接口请求
- 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>