Rest Assured介绍及基本使用
Rest-Assured介绍
官方简单介绍
1 | Testing and validating REST services in Java is harder than in dynamic languages such as Ruby and Groovy. REST Assured brings the simplicity of using these languages into the Java domain. |
在 REST Assured 的官方 GitHub 上有这样一句简短的描述: Java DSL for easy testing of REST services 简约的 REST 服务测试 Java DSL
Rest-Assured是一个测试RESTful Web Services的Java类库。可以使用Rest-Assured编写高度自定义化的HTTP请求用来测试各种各样Restful服务组合的业务实现。
Rest-Assured同样能够验证从服务器返回的HTTP响应报文,例如服务器响应状态码,响应报文内容等,Rest-Assured可以灵活的用来进行Restful Webservice测试。
用Java做接口自动化测试首选REST Assured,具体原因如下:
开源
简约的接口测试DSL
支持xml json的结构化解析
支持xpath jsonpath gpath等多种解析方式
对spring的支持比较全面
Rest-Assured使用
基本三步曲
接口进行测试一般由三步曲
- 传参
- 发请求
- 响应结果断言
REST Assured给我们提供了清晰的三步曲,以given、when、then的结构来实现,基本写法如下:
1 | //使用参数 |
分步解析
分步拆解一:Given
发送请求经常需要带有参数,使用given()就可以实现,如下很多传参方法如下:
在传参的方法中包含了 param
、pathParam
、queryParam
和 formParam
,下面来研究下这几个传参方法的区别
- param
通常我们都会使用 given().param 方法来传参,REST Assured 会根据 HTTP 方法自动尝试确定哪种参数类型(即查询或表单参数),如果是 GET,则查询参数将自动使用,如果使用 POST,则将使用表单参数;
- queryParam 和 formParam
有时候在 PUT 或 POST 请求中,需要区分查询参数和表单参数时,就需要使用queryParam 和 formParam 方法了,具体写法如下:
1 | given(). |
- pathParam
使用given时指定请求路径的参数,这个方法很少用到,具体写法如下:
1 | given(). |
- header/headers
经常还需要在请求头中带入参数,这个时候就可以使用header或headers方法,写法如下:
1 | given() |
或者用headers将多个参数写在一起:
1 | given() |
- cookie
有时候需要在请求中带入cookie,restassured提供了cookie方法来实现:
1 | given() |
- contentType
经常还会设置contentType
,最常见的就是application/json
了,写法如下:
1 | given().contentType("application/json"). .. |
- body
在POST, PUT 或 DELETE请求中,我们经常还需要带上请求体body,写法如下:
1 | given().body("{\n" + |
也可以用request更为明确的指出是请求body:
1 | given().request().body("{\n" + |
- 没有参数
如果我们没有参数需要传递,也可以省略掉**given()**:
1 | get("/lotto").then().assertThat().body("lotto.lottoId", equalTo(5)); |
- proxy
有时候我们需要进行接口的调试,抓包是最常用的一种方式,rest-assured 提供了 proxy 方法,可以设置代理,写法如下:
1 | given().proxy("127.0.0.1",8888). .. |
分步拆解二:When
- when主要用来触发请求,在when后面接着请求URL:
1 | given().when().post("http://xx.xxx.xxx.xx/auth/oauth/token"). .. |
- 前面在given中我们设置了很多请求参数,在when中也可以设置,只不过要注意的是在请求之前设置;这也比较好理解,如果再请求之后的话,参数都设置怎么发请求呢?
1 | given() |
分步拆解二:Then
then后面可以跟断言,也可以获取响应值
- 断言-then().body()
then().body() 可以对响应结果进行断言,在 body 中写入断言:
1 | .. post("http://xx.xxx.xxx.xx/auth/oauth/token") |
其中statusCode(200)是对状态码的断言,判断状态码是否为200;body(“code”,equalTo(1))是对返回体中的code进行断言,要求返回code值为1
注意:这里的equalTo使用的是hamcrest断言
- 获取响应-then().extract().body().path(“code”)
我们可以在then后面利用.extract().body() 来获取我们想要body的返回值,它们也可以直接接在断言后面,写法如下:
1 | .. .then() |
注意:这里的body() 不要和请求体body()以及断言的body()混淆了
接口鉴权
鉴权–API的安全问题,在请求时都需要带上鉴权认证,Rest-Assured支持多种鉴权方式(可查看官网),下面就介绍常见的几种鉴权方式
oauth2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17/**
* 查询GitHub的repo信息--oauth2
* auth().oauth2() 该方式是将token信息隐式在请求体重
* auth().preemptive().oauth2() 显示将鉴权信息在header中携带
* 直接指定header参数进行鉴权 header("Authorization", "token xxxxxx")
*/
void queryRepoOauth() {
given().log().all()
//.auth().oauth2("token")
//.auth().preemptive().oauth2("token")
.header("Authorization", "token token")
.when()
.get("https://api.github.com/user/repos")
.then()
.log().all();
}
basic
1
2
3
4
5
6
7
8
9
10
11
12
13/**
* 查询GitHub的repo信息--basic
* basic("username", "password") 中的username和password替换为自己的GitHub的用户名和密码即可
*/
void queryRepoBasic() {
given().log().all()
.auth().preemptive().basic("username", "password")
.when()
.get("https://api.github.com/user/repos")
.then()
.log().all();
}
请求处理实战
创建Maven项目,并引入依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>${rest-assured.version}</version>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>json-path</artifactId>
<version>${rest-assured.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
以RESTFul接口实例接口为例,针对于RESTful的接口,进行请求处理
接口文档,启动工程后,请求地址:http://ip:port/doc.html
请求实战
- Get请求
- POST请求
- PUT请求
- DELETE请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134package com.api.demo;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
/**
* Rest-Assured请求处理,发送不同的Request
*
* @author jingLv
* @date 2021/01/04
*/
public class TestApi {
private static String token;
private static final Integer USER_ID = 1;
static void setUp() {
RestAssured.baseURI = "http://localhost:8886/v1";
String loginBody = "{\n" +
" \"username\":\"xiaohong\",\n" +
" \"password\":\"123123\"\n" +
"}";
token = given()
.when()
.contentType("application/json")
.body(loginBody)
.get("/user/login")
.then()
.log().body()
.extract().response().path("data.token");
}
/**
* 发送post请求 -- 创建用户信息
*/
void addUserInfo() {
String userInfoBody = "{\n" +
" \"userId\":" + USER_ID + ",\n" +
" \"userName\":\"小红\",\n" +
" \"email\":\"xiaohong@qq.com\",\n" +
" \"phone\":\"18623456543\",\n" +
" \"friends\":[\n" +
" {\n" +
" \"userId\":11,\n" +
" \"userName\":\"小红喵\",\n" +
" \"email\":\"xiaohongmiao@qq.com\",\n" +
" \"phone\":\"18623456555\"\n" +
" },\n" +
" {\n" +
" \"userId\":12,\n" +
" \"userName\":\"小红旺\",\n" +
" \"email\":\"xiaohongwang@qq.com\",\n" +
" \"phone\":\"18623456566\"\n" +
" }\n" +
" ]\n" +
"}";
given()
.log().all()
.contentType(ContentType.JSON)
.header("token", token)
.body(userInfoBody)
.when()
.post("/info/user")
.then()
.log()
.status().statusCode(200);
}
/**
* 发送get请求 -- 查询所有用户信息
*/
void findAllUserInfo() {
given()
.log().all()
.contentType(ContentType.JSON)
.header("token", token)
.when()
.post("/info/user")
.then()
.log()
.status().statusCode(200);
}
/**
* 发送put请求 -- 更新指定用户的部分信息
*/
void updateUserInfoByUserId() {
String updateUserInfoById = "{\n" +
" \"userId\":" + USER_ID + ",\n" +
" \"userName\":\"小红红\",\n" +
" \"email\":\"xiaohong红@qq.com\",\n" +
" \"phone\":\"18623456543\"\n" +
"}";
given()
.log().all()
.contentType(ContentType.JSON)
.header("token", token)
.body(updateUserInfoById)
.when()
.put("/info/user/" + USER_ID)
.then()
.log()
.status().statusCode(200);
}
/**
* 发送delete请求 -- 删除指定用户信息
*/
void deleteUserInfoByUserId() {
given()
.log().all()
.contentType(ContentType.JSON)
.header("token", token)
.when()
.delete("/info/user/" + USER_ID)
.then()
.log()
.status().statusCode(200);
}
}