rest-assured接口测试学习(三)

前文:
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
                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使用

  1. 导入依赖

    io.rest-assured
    json-schema-validator
    3.0.1

  1. 一般Schema的文件比较大,使用时,通常存成一个的文件。


  2. 调用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请求

你可能感兴趣的:(rest-assured接口测试学习(三))