基于Java+HttpClient+TestNG的接口自动化测试框架(四)-------参数存取处理

本文主要是介绍基于Java+HttpClient+TestNG的接口自动化测试框架(四)-------参数存取处理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在真正开始接口测试之前,我们需要对参数的处理进行梳理。这里所说的“参数”,既包含之前在xml中的配置(我们称之为全局参数),也包含在每一条用例中书写的param。全局参数为固定不变的,而根据接口相应获取的数据是动态变化的。
之前我们已经用${param_name}的形式,定义了如何从公共参数池中调用所需要的参数。
并且当一个接口的请求发送完成,进行下一个接口操作的时候,我们也需要对相应的数据进行处理。例如,前面一个接口的响应中出现了下一个接口需要使用的数据,比如id,password,token等等。那么需要对这些数值进行操作(保存·),把获取到的数据存入这个公共参数池中,然后在后续的接口请求中调用这些数据。
对于作为测试用例数据的格式,我们可以把它设计成这样的。
www.wityx.com

       在这里,我们可以看到,在url,header,param中,我们使用了${param_name}的形式,这些变量可以从我们的公共参数池中取得,而后面的verify,可以对返回值使用JSONPath来精准判定。而对于,save中的内容,我们可以将其存入公共参数池,供后面的接口进行调用。

接下来,我们逐步来作成TestBase的基础类,在这个类中,我们来逐步定义如何处理参数以及如何来使用参数。在这个类中,牵涉到很多关联调用的其他工具类,在本篇中暂时不做说明。在之后的章节中来逐步去说明调用关系。
PS:在我们写一个程序时,如果一时不能把程序的构造想清楚,可以先用自然语言把整体逻辑描述清楚,具体的代码可以之后再进行斟酌。
  首先,我们先需要定义一个公共参数池,以及对应与${param_name}的正则表达式。
 
    /*** 公共参数数据池(全局可用)*/private static Map<String, String> saveDatas = new HashMap<String, String>();/*** 替换符,如果数据中包含“${}”则会被替换成公共参数中存储的数据*/protected Pattern replaceParamPattern = Pattern.compile("\\$\\{(.*?)\\}");/*** 获取公共数据池中的数据* * @param key*            公共数据的key* @return 对应的value*/protected String getSaveData(String key) {if ("".equals(key) || !saveDatas.containsKey(key)) {return null;} else {return saveDatas.get(key);}}protected void setSaveDatas(Map<String, String> map) {saveDatas.putAll(map);}

  在使用过程中,我们可以将参数分为两类。第一类为全局参数,意思是可以将之前从xml中读取的配置,作为全局参数存入公共参数数据池,在整个接口测试运行的过程中均可进行调用。第二类是,接口过程中产生对的过程参数,即,接口A返回的数据,可以作为参数使用在接口B的请求中。这类参数在接口请求执行过程中进行定义,也存入公共参数池。

  这两类参数,均使用${param_name}的形式进行调用。来看下面一段代码:

    /*** 取公共参数 并替换参数,处理${}* @param param* @return*/protected String getCommonParam(String param) {if (stringUtil.isEmpty(param)) {     //stringUtil后续进行说明return "";}Matcher m = replaceParamPattern.matcher(param);// 取公共参数正则while (m.find()) {String replaceKey = m.group(1);// 如果公共参数池中未能找到对应的值,该用例失败。
            Assert.assertNotNull(replaceKey,String.format("格式化参数失败,公共参数中找不到%s。", replaceKey));String value;// 从公共参数池中获取值value = getSaveData(replaceKey);//如果值不为空,则将参数替换为公共参数池里读取到的value的值。if(null != value) {param = param.replace(m.group(), value);//如果值为空,则将参数替换为字符串“null”}else {param = param.replace(m.group(), "null");}}return param;}

  这里使用了正则表达式来匹配参数中出现的${XXXX}形式的字符串。这一段的主要思想为,使用定义好的正则表达式来匹配param的字符串,如果匹配的到,则进行循环,把匹配到的第一个字符串(基本就是1个字符串)作为key,然后到saveData的Map中取得对应的值,并返回。

  这样,我们就实现了使用${param_name}的形式,调用公共参数池的目的。

  那么说完了“取参数”,我们还需要说一下“存参数”。在接口测试执行的过程中,假如我想把某个返回的值作为参数,存入公共参数池中,我们应该怎么做呢?

    /*** 提取json串中的值保存至公共池中* * @param json*            将被提取的json串。* @param allSave*            所有将被保存的数据:xx=$.jsonpath.xx;将$.jsonpath.*            xx提取出来的值存放至公共池的xx中*/protected void saveResult(String json, String allSave) {if (null == json || "".equals(json) || null == allSave|| "".equals(allSave)) {return;}allSave = getCommonParam(allSave);String[] saves = allSave.split(";");String key, value;for (String save : saves) {Pattern pattern = Pattern.compile("([^;=]*)=([^;]*)");Matcher m = pattern.matcher(save.trim());while (m.find()) {key = getBuildValue(json, m.group(1));  //getBuildValue的方法后续说明value = getBuildValue(json, m.group(2));reportUtil.log(String.format("存储公共参数   %s值为:%s.", key, value));saveDatas.put(key, value);}}}

  这里我们在save时,同样是通过正则表达式来进行匹配,具体的形式类似于 aa=$.Content.User 的形式,即变量名=JSONPath,将JSONPath找到的值来赋此变量,并存储到公共参数池中。

  这里提到了一个getBuildValue的方法,具体的代码如下:

/*** 获取格式化后的值* * @param sourchJson* @param key* @return*/private String getBuildValue(String sourchJson, String key) {key = key.trim();Matcher funMatch = funPattern.matcher(key); //funPattern为函数匹配正则表达式,后续进行说明if (key.startsWith("$.")) {// 如果为JSONPath,获取该JSONPath对应的值(对象)    Object x = JSONPath.read(sourchJson, key);
       //空值处理
if(x == null) {key = (String)x;}else {key = x.toString();}
       //如果匹配到的是自定义函数,则先解析该自定义函数的参数,若该自定义函数的参数中有JSONPath,则对该JSONPath取值,并对应转成字符串对象。}
else if (funMatch.find()) {String args = funMatch.group(2);String[] argArr = args.split(",");for (int index = 0; index < argArr.length; index++) {String arg = argArr[index];if (arg.startsWith("$.")) {argArr[index] = JSONPath.read(sourchJson, arg).toString();}}String value = functionUtil.getValue(funMatch.group(1), argArr); // functionUtil为自定义函数工具类,后续说明key = stringUtil.replaceFirst(key, funMatch.group(), value);}return key;}

  那么,通过以上的代码,我们可以较为清晰的看到,我们设计了这个公共参数池,来对全局参数和过程参数进行管理,即可取也可存。方便了在之后的代码中进行调用。

   在上面的代码中,我们出现了一个stringUtil的工具类,这算是一个字符串处理工具。请看以下代码:

public class stringUtil {public static boolean isNotEmpty(String str) {return null != str && !"".equals(str);}public static boolean isEmpty(String str) {return null == str || "".equals(str);}/*** * @param sourceStr 待替换字符串* @param matchStr  匹配字符串* @param replaceStr  目标替换字符串* @return*/public static String replaceFirst(String sourceStr,String matchStr,String replaceStr){int index = sourceStr.indexOf(matchStr);int matLength = matchStr.length();int sourLength = sourceStr.length();String beginStr = sourceStr.substring(0,index);String endStr = sourceStr.substring(index+matLength,sourLength);sourceStr = beginStr + replaceStr + endStr;return sourceStr;}}

  这个工具类中,写了判定字符串是否为空的方法,还有一个替换首个匹配字符串的方法。有兴趣的童鞋可以自行继续扩展。

  

这篇关于基于Java+HttpClient+TestNG的接口自动化测试框架(四)-------参数存取处理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/986919

相关文章

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

Nginx设置连接超时并进行测试的方法步骤

《Nginx设置连接超时并进行测试的方法步骤》在高并发场景下,如果客户端与服务器的连接长时间未响应,会占用大量的系统资源,影响其他正常请求的处理效率,为了解决这个问题,可以通过设置Nginx的连接... 目录设置连接超时目的操作步骤测试连接超时测试方法:总结:设置连接超时目的设置客户端与服务器之间的连接

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Java判断多个时间段是否重合的方法小结

《Java判断多个时间段是否重合的方法小结》这篇文章主要为大家详细介绍了Java中判断多个时间段是否重合的方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录判断多个时间段是否有间隔判断时间段集合是否与某时间段重合判断多个时间段是否有间隔实体类内容public class D

IDEA编译报错“java: 常量字符串过长”的原因及解决方法

《IDEA编译报错“java:常量字符串过长”的原因及解决方法》今天在开发过程中,由于尝试将一个文件的Base64字符串设置为常量,结果导致IDEA编译的时候出现了如下报错java:常量字符串过长,... 目录一、问题描述二、问题原因2.1 理论角度2.2 源码角度三、解决方案解决方案①:StringBui

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

Java中ArrayList和LinkedList有什么区别举例详解

《Java中ArrayList和LinkedList有什么区别举例详解》:本文主要介绍Java中ArrayList和LinkedList区别的相关资料,包括数据结构特性、核心操作性能、内存与GC影... 目录一、底层数据结构二、核心操作性能对比三、内存与 GC 影响四、扩容机制五、线程安全与并发方案六、工程

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.