前文:
rest-assured接口测试学习(一)
rest-assured接口测试学习(二)
补充知识
一、全局封装
1.全局RestAssured对象
-
RestAssured.XXX
全局变量 - BaseURI
2.spec方法通用的断言
每个请求都会共用的参数:比如URI 、cookies,或者每个接口都有的断言statusCode是200……可以使用specification
public class Baidu {
public static RequestSpecification requestSpecification;
public static ResponseSpecification responseSpecification;
@Before
public void gen(){
//通用请求
requestSpecification=new RequestSpecBuilder().build();
requestSpecification.port(80);
requestSpecification.cookie("s_id","leitianxiao");
requestSpecification.header("User-Agent","Andriod");
//通用断言
responseSpecification=new ResponseSpecBuilder().build();
responseSpecification.statusCode(200);
responseSpecification.body(hasItems("0","1"));
//其他用例里使用
@Test
public void testGetHtml(){
given().
//请求使用
spec(requestSpecification);
get("http://www.baidu.com").
then().
//断言使用
spec(responseSpecification);
}
}
3.filter方法进行加解密封装(利用filter机制实现自动解密)
(这里没大懂~~)
- filter可以用于全局请求
- request处理
记录所有的request数据
自动填充token - response处理
重新构建新的response
filter((req,res,ctx)->{//重新生成response})
new ResponseBuilder().clone(originalResponse)
————————————
filter相当于过滤器、拦截器,在请求之前可以改掉请求信息,如URL,然后传给ctx调用链,调用链发送篡改后的请求,调用链获得response,可以进行篡改,篡改之后才会返回response
顺序:
//code
//filter request
//real response
//filter response
//return response
//then断言
解密原理是在得到real response进行解密,通过filter response把解密的response返回。
tips:
这里maven构建时报错-source 1.5 中不支持 lambda 表达式
,filter((req,res,ctx)->{//重新生成response})
是jdk8的 lambda 表达式,Maven Compiler 插件默认会加 -source 1.5 及 -target 1.5 参数来编译(估计是为了兼容一些比较老的 Linux 服务器操作系统,它们通常只有 JDK 5),而我们的代码里使用了 JDK 7/8 的语法。
解决:pom.xml文件
org.apache.maven.plugins
maven-compiler-plugin
3.8.1
1.8
————————————
- 修改request
可以修改请求文件(自动带上cookie)
通用的请求数据记录(记录所有的请求和响应)
public void testUserInfo(){
given().log().all().proxy("127.0.0.1").//设置代理抓包
filter((req,res,ctx)->{
//自行给请求头加上id=tester字段
req.header("id","tester");
//把请求发出去
Response resOrigin=ctx.next(req,res);
//把响应返回
return resOrigin;
}).
when().
get("/data/userinfo").
then().log().all().
spec(responseSpecification);
}
通过charles可以看到,请求头里有了id=tester字段,但是用log().all()
打印没有,这说明在真实请求发起时,并不知道有id这个字段,通过filter后,在真实对外发送时增加了这个字段。
应用:
全局的filter,所有请求加一个通用的请求信息(比如cookie)放在@Before,可以通过if判断。
RestAssured.filter((req,res,ctx)->{
//如果URI里包含xueqiu.com,请求头上加上cookie信息
if (req.getURI().contains("xueqiu.com")){
//自行给请求头加上id=tester字段
req.header("cookie","……");
//把请求发出去
Response resOrigin=ctx.next(req,res);
//把响应返回
return resOrigin;
} }).
——————————
- 修改response
示例:
given().filter((req,res,ctx)->{
//把请求发出去
Response resOrigin=ctx.next(req,res);
//克隆原来的response
ResponseBuilder responseBuilder=new ResponseBuilder().clone(resOrigin);
//setbody是修改把返回来的body
responseBuilder.setBody("hello world");
//新的response
Response resNew =responseBuilder.build();
//返回新的response
return resNew;
})
应用:
{
"q": "sogo",
"page": 1,
"size": 3,
"stocks": [{
"code": "SOGO",
"name": "搜狗",
"enName": "",
"hasexist": "false",
"flag": null,
"type": 0,
"stock_id": 1029472,
"ind_id": 0,
"ind_name": "通讯业务",
"ind_color": null,
"_source": "sc_1:1:sogo"
}]
}
响应原本是这种json格式,我们的断言是
then().
statusCode(200).
body("stocks.name",equalTo("搜狗"));
可能因为某些原因,响应需要加密(以base64加密为例),返回的是加密的响应,这个时候你使用业务断言是会报错的:
ewoJInEiOiAic29nbyIsCgkicGFnZSI6IDEsCgkic2l6ZSI6IDMsCgkic3RvY2tzIjogW3sKCQkiY29kZSI6ICJTT0dPIiwKCQkibmFtZSI6ICLmkJzni5ciLAoJCSJlbk5hbWUiOiAiIiwKCQkiaGFzZXhpc3QiOiAiZmFsc2UiLAoJCSJmbGFnIjogbnVsbCwKCQkidHlwZSI6IDAsCgkJInN0b2NrX2lkIjogMTAyOTQ3MiwKCQkiaW5kX2lkIjogMCwKCQkiaW5kX25hbWUiOiAi6YCa6K6v5Lia5YqhIiwKCQkiaW5kX2NvbG9yIjogbnVsbCwKCQkiX3NvdXJjZSI6ICJzY18xOjE6c29nbyIKCX1dCn0=
tips:
base64
命令可以直接将响应转为base64加密形式
用python快速生成一个本地8000端口的小网站来演示这种情况:
vim base64.json
//把加密了的json内容写入base64.json中
python -m CGIHTTPServer
@Test
public void testBase64(){
given().
get("http://127.0.0.1:8000/base64.json").prettyPeek().
then().
statusCode(200).
body("stocks.name",hasItems("搜狗"));
}
把上文的示例中responseBuilder.setBody("hello world");
的“hello world”改为解密后的响应body即可。
代码如下:
@Test
public void testBase64(){
given().filter((req,res,ctx)->{
//把请求发出去
Response resOrigin=ctx.next(req,res);
//克隆原来的response
ResponseBuilder responseBuilder=new ResponseBuilder().clone(resOrigin);
//使用Base64的库
//Base64.getDecoder().decode()对resOrigin的body进行解码
//转为string格式,trim()去掉字符串两端多余空格。
String decode=new String(
Base64.getDecoder().decode(
resOrigin.body().asString().trim()
)
);
//setbody是修改把返回来的body
responseBuilder.setBody(decode);
//新的response
Response resNew =responseBuilder.build();
//返回新的response
return resNew;
}).
get("http://127.0.0.1:8000/base64.json").prettyPeek().
then().
statusCode(200).
body("stocks.name",hasItems("搜狗"));
}
}
解密之后可以正常使用我们的业务断言
二、对接口时间进行断言
when().
get("/lotto").
then().
time(lessThan(2000L));//响应时间不超过2000毫秒
除了进行功能测试,对响应时间有个基本的要求
三、schema自动校验
RestAssured有一套自己的schema自动校验机制
- schema的生成借助于在线服务
- 使用schema api断言
schema自动生成方法
(需要很深的算法功底,自己写工具,自动扫描公司接口,自动生成对应的schema文件)
- 每次运行的时候自动保存当前的schema
- 下次运行对比上次的schema如果发现变更就报错
- saveSchema+diffSchema
实践
官网:JSON Schema
作用:JSON Schema可以对JSON进行注释和校验,我们对一个接口的断言最多写10个左右,对其余大量的数据的response没有校验,JSON Schema就是对大量数据的Json进行一个数据格式的验证,包括字段的数据类型、范围、长度。
-
生成schema文件:Json Schema Tool
$schema
关键字指出此架构是根据标准的特定草稿编写的,"$schema": "http://json-schema.org/draft-07/schema#"
表示根据draft-07草案编写。
该$id
关键字定义模式的URI,并解析模式中其他URI引用的基URI。
$title
和$description
注释关键字仅是描述性的。它们不会对要验证的数据添加约束。使用这两个关键字说明了模式的意图。
type
验证关键字定义我们的JSON数据的第一个约束,在这种情况下,它必须是一个JSON对象。"type": "object"
验证类型是object,"type": "array"
验证类型是数组,"type": "boolean"
验证类型是布尔类型。
$required
验证key字段的列表。
properties
验证关键字。 -
手工编辑增强
例:String断言,对所有type为String的进行断言,长度在5-10之间
所以可以通过手动添加这个字段来约束JSON数据。 如何在RestAssured使用
- 导入依赖
io.rest-assured
json-schema-validator
3.0.1
-
一般Schema的文件比较大,使用时,通常存成一个的文件。
调用matchesJsonSchemaClasspath等系列方法
静态导入:import static io.restassured.module.jsv.JsonSchemaValidator.*;
常用断言方式一:assertThat().body(matchesJsonSchemaInClasspath("data/userInfo-schema.json"));
常用断言方式二:assertThat().body(matchesJsonSchema(new File("data/userInfo-schema.json")));
故意写错一个验证类型看看效果,把本应该是string类型的改为boolean。
warning可以先不管,找到error~可以看出说实例类型是string,而被允许的类型是boolean。
四、https请求
useRelaxedHTTPSValidation();
//信任https请求