美文网首页
2020-05-12Api测试用例参数化

2020-05-12Api测试用例参数化

作者: testerPM | 来源:发表于2020-05-12 09:43 被阅读0次

    问题: 为什么要做参数化?

    1.以注册接口的测试用例为例: 接口参数mobile_phone目前在excel中是写死的,执行脚本测试该接口,下一次如果再重新执行,就要重新改excel中的mobile_phone以及pwd,我们不想每次都手动修改excel,如果能在程序中每次执行脚本都可以自动获取到一个随机的mobile_phone和pwd,这样每次重新执行脚本测试接口,就能保证每个测试用例都能被执行


    image.png
    1. 下图是充值接口,member_id也是写死的,是从数据库中查到这个登陆用户的member_id,如果将member_id进行参数化,直接读进来,这样程序脚本是不是更灵活呢?


      image.png

    如何进行参数化呢?

    1.以注册用例
    手机号和密码作为参数化获取,不过这里,我们一般对传入正确手机号,密码进行参数化,错误的手机号,密码不用进行参数化,因为只有正确的数据,下次执行脚本才会有影响(如:手机号被注册过了,就无法注册成功了,那么注册成功的case就不能被执行)


    image.png

    检验sql 也要替换成参数化


    image.png

    2.充值接口

    image.png
    image.png

    如何进行参数化替换?

    如何把 {toBeRegisterMobilephone},{toBeRegisterPassword}替换成具体的值呢?

    //获取接口参数
    cases.getParams();
        //获取到接口参数如下 
    {"mobile_phone":"${toBeRegisterMobilephone}","pwd":"${toBeRegisterPassword}"}
    //问题: 怎么把上面的json 转换下面的json呢???
            {"mobile_phone":"13333333333","pwd":"222222"}
    
    
    

    解决办法如下:加到常量类,常量类新增如下代码:

    public class Constant {
        //接口参数字段
        public  static final String  REGISTER_MOBILEPHONE_TEXT="${toBeRegisterMobilephone}";
        public  static final String  REGISTER_PASSWORD_TEXT="${toBeRegisterPassword}";
        public  static final String  LOGIN_MOBILEPHONE_TEXT="${toBeLoginMobilephone}";
        public  static final String  LOGIN_PASSWORD_TEXT="${toBeLoginPassword}";
        public  static final String  MEMEBER_ID="${member_id}";
        //接口参数值
        public  static final String  REGISTER_MOBILEPHONE_VALUE="18999999999";
        public  static final String  REGISTER_PASSWORD_VALUE="123456";
        public  static final String  LOGIN_MOBILEPHONE_VALUE="18999999999";
        public  static final String  LOGIN_PASSWORD_VALUE="123456";
        
    
    
    
    }
    
    
    

    参数替换字段和参数值如何发生关联呢???

    即:REGISTER_MOBILEPHONE_TEXT和REGISTER_MOBILEPHONE_VALUE如何关联起来呢???

    解决办法:使用map

    (1)AuthenticationUtils.java类中已定义好一个个map
    public class AuthenticationUtils {
        // 静态变量
        public static Map<String, String> env = new HashMap<String, String>();
    }
    
    (2)将参数放进map

    以登录为例:LoginCase.java类加入以下新增代码

        @BeforeSuite
        public  void  init() {
            //套件执行初始化:配置参数化变量
            AuthenticationUtils.env.put(Constant.REGISTER_MOBILEPHONE_TEXT,Constant.REGISTER_MOBILEPHONE_VALUE);
            AuthenticationUtils.env.put(Constant.REGISTER_PASSWORD_TEXT,Constant.REGISTER_PASSWORD_VALUE);
            AuthenticationUtils.env.put(Constant.LOGIN_MOBILEPHONE_TEXT,Constant.LOGIN_MOBILEPHONE_VALUE);
            AuthenticationUtils.env.put(Constant.LOGIN_PASSWORD_TEXT,Constant.LOGIN_PASSWORD_VALUE);
        
        
        }
        
    
    
    

    member_id是不能通过初始化加进去,因为member_id是需要通过动态获取的(JSONPath从响应体中获取)
    AuthenticatonsUtils.java新增代码

    // 2.获取member_id
                Object memberId = JSONPath.read(responseBody, "$.data.id");
                if (memberId != null) {
                    env.put("memberId", memberId.toString());
    
                }
    
    
    
    public class AuthenticationUtils {
        // 静态变量
        public static Map<String, String> env = new HashMap<String, String>();
    
        public static void storeToken(String responseBody) {
            // 1 取出token---jsonpath提供的语法格式取
            // $代表从根元素开始找,一层层找下去
            Object token = JSONPath.read(responseBody, "$.data.token_info.token");// 如果找不到返回的是null
    
            // 2 存储token
            if (token != null) {
                env.put("token", token.toString());// token是Object类型,对象转字符串才可以存进去,因为env Map<String,String> 是String
                // 2.获取member_id
                Object memberId = JSONPath.read(responseBody, "$.data.id");
                if (memberId != null) {
                    env.put("memberId", memberId.toString());
    
                }
    
            }
        }
    }
    
    
    
    (3)循环遍历key:

    map遍历---》这里是把key放到set集合,然后增强for循环进行遍历
    一共就有五个key,逐一判断params中是否有这五个key,params中只要有key就替换成value

    String params = cases.getParams();// 获取第1个,第2个,第3个......用例接口参数(用例一个个读进来)
    
            Set<String> keySet = AuthenticationUtils.env.keySet();// 获取key集合
            //为何要进行遍历:这样做就不用知道params中使用到了哪些参数变量,当读取第一个用例时,通过遍历所有的key,第一个用例params中只要有key就替换成value
            for (String key : keySet) {
                String keyValue = AuthenticationUtils.env.get(key);// 获取key的值
                params.replace(key, keyValue);// params是否包含key,如果有key,就将其替换成keyValue,没有就不替换
                // 遍历完所有的key会自动跳出循环
            }
    

    上面代码抽取优化到BaseCase.java类中:新增代码如下

        /**
         * 参数化变量替换
         * @param params
         * @return
         */
        public String parmasReplace(String params) {
    
            Set<String> keySet = AuthenticationUtils.env.keySet();// 获取key集合
            // 为何要进行遍历:这样做就不用知道params中使用到了哪些参数变量,通过遍历所有的key(一共就有四个key,逐一判断params中是否有key,params中只要有key就替换成value)
            for (String key : keySet) {
                String keyValue = AuthenticationUtils.env.get(key);// 获取key的值
                params.replace(key, keyValue);// params是否包含key,如果有key,就将其替换成keyValue,没有就不替换
                // 遍历完所有的key会自动跳出循环
            }
            return params;
        }
    
    
    

    LoginCase.java类进行调用上述方法即可:


    image.png

    到此代码就写完了,执行LoginCase.java


    image.png

    从上图可以看到有两个错误,第一:参数没有替换成功, 第二,报了空指针

    (1)先看第一个错误,为什么没有被替换成功
    图1:可以看到所有的key,按f6执行下一步到图2


    image.png

    图2:可以看到key对应的value就是图3中的值


    image.png

    图3:按f6执行到下一步 图4


    image.png

    图4: 下图key的values是图5


    image.png
    图5:按f6执行下一步遍历结束后执行 到图6
    image.png

    图6:下图可以看到,返回值没有被替换

    image.png

    原因定位:params = params.replace(key, keyValue);需用变量接收替换后的值

    image.png

    (2)为什么会报空指针

    image.png

    上图报错,第一行提示报错出在 BaseCase.java:62行,点击此处会自动跳到报错的地方


    image.png

    分析第62行代码,key,keyValued都有值,不会为空,那么问题就出在传进来参数params可能为空,空对象调方法一般会报空指针,再看报错第二行,可以看到params是哪里传进来的


    image.png

    上图可以分析得到:传入的sql为空,所以需要优化代码:BaseCase.java类优化参数替换方法parmasReplace()

        /**                                                                                                                                              
         * 参数化变量替换                                                                                                                                       
         *                                                                                                                                               
         * @param params                                                                                                                                 
         * @return                                                                                                                                       
         */                                                                                                                                              
        public String parmasReplace(String params) {            
    //判断params为空的处理                                                                                         
            if (StringUtils.isBlank(params)) {                                                                                                           
                return "";                                                                                                                               
            }                                                                                                                                            
                                                                                                                                                         
            Set<String> keySet = AuthenticationUtils.env.keySet();// 获取key集合                                                                             
            // 为何要进行遍历:这样做就不用知道params中使用到了哪些参数变量,通过遍历所有的key(一共就有四个key,逐一判断params中是否有key,params中只要有key就替换成value)                                          
            for (String key : keySet) {                                                                                                                  
                String keyValue = AuthenticationUtils.env.get(key);// 获取key的值                                                                            
                                                                                                                                                         
                params = params.replace(key, keyValue);// Primes是否包含key,如果有key,就将其替换成keyValue,没有就不替换                                                     
                // 遍历完所有的key会自动跳出循环                                                                                                                      
            }                                                                                                                                            
            return params;                                                                                                                               
        }                                                                                                                                                
    
    

    备注:

    (1)注册和充值接口参数替换代码自行补充(只需要在各自的类进行调用替换方法即可),即:将下面代码分别copy到RegisterCase.java,RechargeCase.java中即可

        //接口参数变量替换
            String params = parmasReplace(cases.getParams());
            System.out.println("替换后的params:" + params);
            //将替换后的params塞到cases对象里
            cases.setParams(params);
            // sql参数替换
            String SQLparams = parmasReplace(cases.getSql());
            System.out.println("替换后的SQLparams :" + SQLparams);
            //替换的后的sql塞到cases对像里面
            cases.setSql(SQLparams);
    
    
    

    (2)如果需要单独运行注册,充值接口,则RegisterCase.java,RechargeCase.java各自都要加上下面代码:

    @BeforeSuite
        public void init() {
            // 套件执行初始化:配置参数化变量
            AuthenticationUtils.env.put(Constant.REGISTER_MOBILEPHONE_TEXT, Constant.REGISTER_MOBILEPHONE_VALUE);
            AuthenticationUtils.env.put(Constant.REGISTER_PASSWORD_TEXT, Constant.REGISTER_PASSWORD_VALUE);
            AuthenticationUtils.env.put(Constant.LOGIN_MOBILEPHONE_TEXT, Constant.LOGIN_MOBILEPHONE_VALUE);
            AuthenticationUtils.env.put(Constant.LOGIN_PASSWORD_TEXT, Constant.LOGIN_PASSWORD_VALUE);
    
        }
    
    

    如果通过执行testNG.xml运行,则RegisterCase.java,RechargeCase.java各自就不需要要加上上面的代码(只要有一个类中有上面的代码即可,因为上面代码是在套件执行之前会将变量加到map里面)

    疑问:执行充值接口为什么${member_id}没有被替换掉呢?

    原因定位:(1)通过打断点,发现map集合key没有MEMBER_ID
    这是为什么呢?-》因为:MEMBER_ID是需要通过登陆才能获取

    Object memberId = JSONPath.read(responseBody, "$.data.id");
                if (memberId != null) {
            
                    env.put("memberId", memberId.toString());
    
    }
    

    所以不能单独运行充值接口,需要依赖登录接口,此时运行通过运行testNG.xml,控制台打印结果发现,${member_id}还是没有被替换

    通过打断点,发现keySet集合还是没有MEMBER_ID
    原因:

       public  static final String  MEMBER_ID="${member_id}";
    错误的写法:
    Object memberId = JSONPath.read(responseBody, "$.data.id");
                if (memberId != null) {
                    //env.put("memberId", memberId.toString());
                                // env.put("MEMBER_ID", memberId.toString());
                            
    }
    
    正确的写法:
    Object memberId = JSONPath.read(responseBody, "$.data.id");
                if (memberId != null) {
            env.put(Constant.MEMBER_ID, memberId.toString());
    }
    
    
    
    

    再次打断点,发现keySet集合有MEMBER_ID(注意:只有member_id不为空才能put进去)


    image.png

    重新执行testNG.xml。控制台打印结果中$ {member_id}替换成功

    待解决问题:为什么下面的写法语法没有报错呢

      // env.put("MEMBER_ID", memberId.toString());
    

    java 随机生成手机号码(自己百度)

    
    
    // 接口参数
        public static final String REGISTER_MOBILEPHONE_TEXT = "${toBeRegisterMobilephone}";
        public static final String REGISTER_PASSWORD_TEXT = "${toBeRegisterPassword}";
        public static final String LOGIN_MOBILEPHONE_TEXT = "${toBeLoginMobilephone}";
        public static final String LOGIN_PASSWORD_TEXT = "${toBeLoginPassword}";
        public static final String MEMBER_ID = "${member_id}";
        // 接口参数值
        public static final String REGISTER_MOBILEPHONE_VALUE = getTel();
        public static final String REGISTER_PASSWORD_VALUE = "123456789";
        public static final String LOGIN_MOBILEPHONE_VALUE = REGISTER_MOBILEPHONE_VALUE;
        public static final String LOGIN_PASSWORD_VALUE = "123456789";
    
        public static int getNum(int start, int end) {
            return (int) (Math.random() * (end - start + 1) + start);
    
        }
    
    //  public static String[] telFirst = "134,135,136,137,138,139,150,151,152,153,154,155,156,157,158,159,130,131,132,133"
    //          .split(",");
    
        private static String getTel() {
    
            String[] telFirst = "134,135,136,137,138,139,150,151,152,153,154,155,156,157,158,159,130,131,132,133"
                    .split(",");
                 // 打印出数组
            System.out.println(Arrays.toString(telFirst));
            int index = getNum(0, telFirst.length - 1);
            String first = telFirst[index];
            String second = String.valueOf(getNum(1, 888) + 10000).substring(1);
            String third = String.valueOf(getNum(1, 9100) + 10000).substring(1);
            return first + second + third;
        }
    
    

    这里有个疑问,为什么定义一个静态全局变量数组【上面被注释掉的代码】,数组是NUll??? 但是放在getTel()方法体方是可以的,这里是为什么呢????
    原因如下:
    public static final String REGISTER_MOBILEPHONE_VALUE = getTel();这句代码在定义静态数组之前,且这里有调用getTel(),且getTel()方法体有使用到telFirst,而此时程序还没有执行到定义静态数组的语句即还没有被加载进来,所以会报null.

    解决办法:把静态数据声明放在最前面,如下图

    package com.lemon.constant;
    
    import java.util.Arrays;
    
    public class Constant {
        public static String[] telFirst = "134,135,136,137,138,139,150,151,152,153,154,155,156,157,158,159,130,131,132,133"
                .split(",");
        public static final String EXCEL_PATH = "src/test/resources/case_v6.xlsx";
        public static final int ACTUAL_RESPONSE_DATA_CELLNUM = 5;
        // 接口参数
        public static final String REGISTER_MOBILEPHONE_TEXT = "${toBeRegisterMobilephone}";
        public static final String REGISTER_PASSWORD_TEXT = "${toBeRegisterPassword}";
        public static final String LOGIN_MOBILEPHONE_TEXT = "${toBeLoginMobilephone}";
        public static final String LOGIN_PASSWORD_TEXT = "${toBeLoginPassword}";
        public static final String MEMBER_ID = "${member_id}";
        // 接口参数值
        public static final String REGISTER_PASSWORD_VALUE = "123456789";
        public static final String REGISTER_MOBILEPHONE_VALUE = getTel();
        public static final String LOGIN_MOBILEPHONE_VALUE = REGISTER_MOBILEPHONE_VALUE;
        public static final String LOGIN_PASSWORD_VALUE = "123456789";
    
        public static int getNum(int start, int end) {
            return (int) (Math.random() * (end - start + 1) + start);
    
        }
    
        private static String getTel() {
            int index = getNum(0, telFirst.length - 1);
            String first = telFirst[index];
            String second = String.valueOf(getNum(1, 888) + 10000).substring(1);
            String third = String.valueOf(getNum(1, 9100) + 10000).substring(1);
            return first + second + third;
        }
    
        public static void main(String[] args) {
            // System.out.println(getTel());
            System.out.println(Arrays.toString(telFirst));
        }
    
    }
    
    
    

    密码随机数(自行百度)

    相关文章

      网友评论

          本文标题:2020-05-12Api测试用例参数化

          本文链接:https://www.haomeiwen.com/subject/ippvnhtx.html