接口测试 使用 rest-assured 的 jsonpath 来进行 json 解析

49875183 for rest-assured · 2017年03月14日 · 最后由 大鹏 回复于 2020年02月20日 · 2716 次阅读

前言

使用 rest-assured 也有一段时间了,虽然这个框架有很多优势,但最钟爱的还是 json 解析这块,对于我这种不爱太动脑子的人来说,拿来主义最适合了😁基本也满足了测试工作的日常所需 ,当然对于无法满足又想一次性解决的问题,也只能自己苦逼的去改八改八了😵 扯远了~

虽然也有在用 JsonPath 但与 rest-assured 的 JsonPath 来说,rest 的更加方便快捷,不过更恶心的 JAONArray 也在用......

示例接口:http://testerhome.com/api/v3/topics.json?limit=40&offset=0&type=last_actived

标准的 JsonPath

https://github.com/jayway/JsonPath
JsonPath 提供了很全的操作 JSON 的方法

  • 获取 topcis 列表

    List<String> topics = JsonPath.read(jsonStr,"$.topics")
    
  • 获取 topcis 第一条记录

    Object topics1 = JsonPath.read(jsonStr,"$.topics[0]");
    
  • 获取 topcis 第一条记录中 title 的值

    String topics1title = JsonPath.read(jsonStr,"$.topics[0].title");
    
  • 获取 topcis 中所有 title 的名称

    List<String> titles = JsonPath.read(jsonStr,"$.topics[*].title");
    
  • 还有一个非常有意思的使用方法,通过属性进行获取
    比如:获取 id=6421 的对象、获取 name == 恒温的

    Object topicid = JsonPath.read(jsonStr,"$.topics[?(@.id == 6421)]");   
    Object topicname = JsonPath.read(jsonStr,"$.topics[*].user[?(@.name == '恒温')]");
    

rest-assured 的 jsonpath

https://github.com/rest-assured/rest-assured/blob/master/json-path/src/main/java/io/restassured/path/json/JsonPath.java

  • 获取 topcis 列表

    List<String> topics = jsonPath.getList("topics");
    
  • 获取 topcis 第一条记录

    String topics1 =jsonPath.getString("topics[0]");
    
  • 获取 topcis 第一条记录中 title 的值

    String topics1title = jsonPath.getString("topics[0].title");
    
  • 获取 topcis 中所有 title 的名称

    List<String> titles = jsonPath.getList("topics.title");
    
  • 和 jsonpath 一样也可以通过属性进行获取
    比如:获取 id=6421 的对象、获取 name == 恒温的

    String topicid = jsonPath.getString("topics.findAll{topics -> topics.id == 6421}");
    String topicname = jsonPath.getString("topics.user.findAll{user -> user.name == '恒温'}");
    

可以看出

  • rest-assured 的语法上比 jsonpath 更加简明易懂,输写简单
  • rest-assured 的取值方式也更加多样化,和 JAONArray 差不多:getString()、getInt()、getList()、getBoolean() 等等
  • 取深层结构一直点下去就可以了,也不用考虑节点是不是列表、对象之类的了

对于测试同学来说,这些是不是非常的方便,也很容易上手呢😁

但是在实际测试过程中单纯的取值判断是不可能满足测试需要,往往还需要对结构进行整体验证,对于这类检查,只能自己苦逼的码代码了,本人非专业开发人士,相关卫道者请轻拍

有需要的同学可以拿去改八改八耍~~ 当然如有问题也请及时CALL我,我也同步修改一下。。。。。。

验证结构相关代码

/**
     * 验证json串结构是否正确
     * @param jsonStr 接口返回的json串
     * @param checkStr 要验证的一级节点字符串,多个值以逗号分隔 便如:"limitedbuy,name"
     * @param checkList 要验证的二级以下节点字符串,目录以冒号分隔,如果是更深目录 只要在二加入路径即可,"limitedbuy:starttime,endtime,limitedbuyinfo;name/setting:name,age"
     * @return String 返回验证的结果集,如果为空,验证成功,如果不为空验证失败
     * @throws IOException
     */
    public static String jsonUtiltest(String jsonStr,String checkStr,String checkList) throws IOException{

        StringBuilder errStr = new StringBuilder();                                 
                JSONObject jsonObj = JSONObject.fromObject(jsonStr);                
                String returncode = jsonObj.getString("returncode");                
                if (returncode.equals("0")){
                    //如果result返回了[]或{}直接跳出循环,告知无值                                 
                    //判断是否有result节点,如果没有就算成功结束                  
                    if(jsonObj.containsKey("result"))
                    {
                        if(!(jsonObj.getString("result").equals("{}")) || !(jsonObj.getString("result").equals("[]"))){
                            if(!jsonObj.getString("result").equals(""))
                            {                               
                                JSONObject jo=null;
                                JSONArray ja = null;
                                Object o = jsonObj.get("result");                               
                                 if(o instanceof JSONObject){
                                        jo = (JSONObject) o;
                                        //先去验证主节点
                                        errStr.append(valjsonobject(jo,checkStr,"result"));                                     
                                        if(checkList.length()>0){
                                            //再去验证子节点                 
                                            String[] strlist = checkList.split(";");    
                                            for (int i = 0; i < strlist.length; i++) {                                              
                                                    String[] childnodeval = strlist[i].split(":");                                                  
                                                    errStr.append(valjsonobject2(jo,childnodeval[0],childnodeval[1]));                          
                                            }       
                                        }
                                }else if(o instanceof JSONArray){
                                    ja = (JSONArray) o;         
                                    for (int i = 0; i < ja.size(); i++) {
                                        //还得先去验证主节点   
                                        errStr.append(valjsonobject(ja.getJSONObject(i),checkStr,"result"));                                        
                                    }               
                                  }
                            }
                        }
                    }                   
                }else{

                     errStr.append("错误码:"+returncode+"\n\r 错误信息:"+jsonObj.getString("message"));                     
                }   
        return errStr.toString();       
    }   

    public static String valjsonobject(JSONObject json ,String checkStr ,String path){

    Iterator it = json.keys(); 
    List<String> keyListstr = new ArrayList<String>();          
        while(it.hasNext()){  
            //遍历json第一层
           keyListstr.add(it.next().toString()); 
        }        
        StringBuilder errStr = new StringBuilder();
        String[] checkStrs = checkStr.split(",");      
        if(checkStrs.length == keyListstr.size()){          
            for (int j = 0; j < checkStrs.length; j++) {                    
                int count = 0;                  
                for (int i = 0; i < keyListstr.size(); i++){                        
                    if (checkStrs[j].equals(keyListstr.get(i))){                            
                        count++;                            
                        if (count > 1 && i == keyListstr.size()-1){//对返回相同的字段进行追加。                                
                            errStr.append(path+"节点下返回相同的字段是:"+checkStrs[j]+".  ");
                        }                           
                    }else{                          
                        if( count < 1 && i == keyListstr.size()-1 ){                                
                            errStr.append(path+"节点下返回的节点缺少字段:"+checkStrs[j]+".  ");                         
                        }
                    }                       
                }
            }                
        }else{          
            if(checkStrs.length < keyListstr.size()){               
                //add判断是否存在相同的字段。
                for (int j = 0; j < checkStrs.length; j++) {                    
                    int count = 0;                          
                    for (int i = 0; i < keyListstr.size(); i++){                                
                        if (checkStrs[j].equals(keyListstr.get(i))){                                    
                            count++;                                    
                            if (count > 1 && i == keyListstr.size()-1){//对返回相同的字段进行追加。                                        
                                errStr.append(path+"节点下返回相同的字段是:"+checkStrs[j]+".  ");
                            }                                       
                        }                               
                    }
                }                    
                //add判断是否存在错误的字段。
                for (int i = 0; i < keyListstr.size(); i++) {                           
                    for (int j = 0; j < checkStrs.length; j++){                             
                        if (keyListstr.get(i).equals(checkStrs[j])){                                    
                            break;                                  
                        }                               
                        else{                                   
                            if(j == checkStrs.length-1 ){                                       
                                errStr.append(path+"节点下多了字段:"+keyListstr.get(i)+".  ");                                   
                            }                                   
                        }                               
                    }
                }
            }else{          
                for (int j = 0; j < checkStrs.length; j++) {                            
                    int count = 0;                          
                    for (int i = 0; i < keyListstr.size(); i++){                                
                        if (checkStrs[j].equals(keyListstr.get(i))){                                    
                            count++;                                    
                            if (count > 1 && i == keyListstr.size()-1){//对返回相同的字段进行追加。                                        
                                errStr.append(path+"节点下返回相同的字段是:"+checkStrs[j]+".  ");
                            }

                        }else{                                  
                            if( count < 1 && i == keyListstr.size()-1 ){                                        
                                errStr.append(path+"节点下缺少字段:"+checkStrs[j]+".  ");                                        
                            }
                        }                               
                    }
                }
            }                
        }        
        return errStr.toString();
     }

    public static String valjsonobject2(JSONObject json ,String path,String checkStr){      

           JSONObject jo=null;
           JSONArray ja = null;
           Object o; 
           String errStr="";
           if(path.contains("/")){
               //拆分路径 
               String[] paths = path.split("/");                   
                   o = json.get(paths[0]);                     
                   path = path.replace(paths[0]+"/", "");
                    //如果子节点是object对象
                   if(o instanceof JSONObject){
                    jo = (JSONObject) o;
                    if(jo.keySet().size()>0){                       
                        errStr = valjsonobject2(jo,path,checkStr);
                    }
                  }else if(o instanceof JSONArray){
                    ja = (JSONArray) o;         
                    for (int i = 0; i < ja.size(); i++) {
                        errStr = valjsonobject2(ja.getJSONObject(i),path,checkStr);
                    }               
                  } 
           }else{              
               o = json.get(path);         
                //如果子节点是object对象
               if(o instanceof JSONObject){
                jo = (JSONObject) o;
                if(jo.keySet().size()>0){
                    errStr = valjsonobject(jo,checkStr,path);
                }
              }else if(o instanceof JSONArray){
                ja = (JSONArray) o;         
                for (int i = 0; i < ja.size(); i++) {
                    errStr = valjsonobject(ja.getJSONObject(i),checkStr,path);
                }               
              }            
           }

           return errStr;
     }
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 14 条回复 时间 点赞

多谢分享,感觉这里是不是太冷清了。

rest-assured 的 jsonpath 解析是否有 bug
String topic= jsonPath.getString("topics.find{topics -> topic.id==" + "20171217THB290187463" + "}");
这种字符串拼接的过滤条件会出错,而将 20171217THB290187463 中的字母改成数字不会报错

13楼 已删除

https://jsonschema.net/ 生成的数据在一些 list 就会出错

49875183 回复

我感觉我被套路了,竟然换头像,害我没认出来。。。

49875183 回复

对啊,比要验证的 json 本身蛋疼多了

49875183 回复

不知道你用过这个没? https://jsonschema.net/

黑水 回复

不过话说写一个特别复杂的 JSON Schema 太恶心了。。。。😓

把老底搂出来啦😁 😁

wsf 回复

😂 rest-assured 还有现成的 org.hamcrest.Matchers ,对于这块我在用 junit,适合现状,够用就好。剩下的就慢慢技术外散就好😂 生活所迫,搞个测试需要懂的越来越多了 唉~~~

😂 josn 数据校验 有个 JSONassert 库,直接拿来用,感觉好 low,jsonschema 验证也是现成的库。。。

49875183 回复

够用就好,喜欢用 JSON Schema 也是因为可以配合 Swagger 、RAML 这种 API 文档。
这样看起来 rest-assured 很不错,如果下份工作不得不用 Java 就去看看😳

黑水 回复

被你说到重点了😂 其实 rest 框架本身就带有这个功能 ,只不过现在我们主脚本了, 这样使用也没有代码量 ,也算适应现在工作模式, 我们也就没有再替换到 jsonschema 之类的了

JSON 有结构描述规范 JSON Schema
比如 Ruby 有 json-schema 这个库实现了 JSON Schema 规范,可以用来验证 JSON 结构,搜了下 Java 也有好几个实现

require "json-schema”

valid_json = '{
                "location": "home",
                "code": 44
              }'
invalid_type_json = '{
                        "location": "home",
                        "code": "44"
                     }'

missing_properties_json = '{
                              "location": "home"
                           }'

schema = '{
            "$schema": "http://json-schema.org/draft-04/schema#",
            "type": "object",
            "properties": {
              "location": {
                "type": "string"
              },
              "code": {
                "type": "integer"
              }
            },
            "required": [
              "location",
              "code"
            ]
          }'

JSON::Validator.validate!(schema, valid_json) # 返回 true
JSON::Validator.validate!(schema, invalid_type_json) # 抛出异常 The property '#/code' of type String did not match the following type: integer
JSON::Validator.validate!(schema, missing_properties_json) # 抛出异常 The property '#/' did not contain a required property of 'code'

厉害了

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册