倒叙看,最新的在上面。。。。

框架设计见我的另一个博客https://blog.csdn.net/weixin_42498050/article/details/115671411

开发不规范的地方:(这就是CR的重要性和要求开发编码规范的重要性)

1 json返回格式非标准,如

序列号:4 cmo获取mec集群列表,正常返回,返回的datacenterid为uuid->4的接口返回为[{}]

2 返回的参数命名不规范,如

cmo注册,正常返回->1  参数命名为_拼接  datacenter_id

DatacenterID

cmo获取mec集群列表,正常返回,返回的datacenterid为uuid->4 返参又为大写的DatacenterID

3 必传参数缺失,接口的Response Code为200(看约定,restful就不正常。普通接口可以返回200,然后json信息告知缺少参数)。接口返回的value都为空-纯空???业界都不这样返回(this is basic knowledge)。

正常来说response code为400 Bad Request或者500 Internal Server Error或者 401 或者别的错误状态码

接口返回为错误状态码和message 如

{
    "code": "0001",
    "msg": "参数无效",
    "data": "BAD_REQUEST"
}

{
    "code": "10002",
    "msg": "参数缺失",
    "data": "BAD_REQUEST"
}

专业版状态码:无论接口文档or开发代码or测试开发自动化代码都有写。现在的公司没有

response status: 200
返回结果: {
 "Mongo_Id": "",
 "id": "",
 "name": "",
 "cluster": "",
 "comment": "",
 "cpu": "",
 "video_type": "",
 "vmcustom_properties": "",
 "run_on": "",
 "run_once": "",
 "vm_ip": ""
}

4 接上面,不传必传参数 response code返回又为400了 上面的为200。不统一。。。。



自动化测试过程中对框架的优化记录

ps 感谢前公司同事欣欣,帅气 技术好 很乖 脾气好 性格好 低调,jar包之王,我搜到的jar包都是收费的,欣欣找的都是免费的。没有欣欣 没有框架

4月22

token鉴权的2种方式,参考博客

Http请求Authorization认证:传Authorization时选择Basic Auth 填写用户名 密码。此次header不需要填写token、X-Auth-Token,需要填写Project

token登录:header需要填写token、X-Auth-Token、Project。当然必不可少的Content-Type:application/json、Accept:application/json

https://blog.csdn.net/weixin_36260016/article/details/114089891

https://blog.iprac.cn/blogs/55.html

String encoding = DatatypeConverter.printBase64Binary("username:passwd".getBytes("UTF-8"));  //username  password 自行修改  中间":"不可少
getMethod.addRequestHeader(new Header("Authorization", "Basic " + encoding));

HTTP Header 详解 -Requests部分

Header 解释 示例
Accept 指定客户端能够接收的内容类型 Accept: text/plain, text/html
Accept-Charset 浏览器可以接受的字符编码集。 Accept-Charset: iso-8859-5
Accept-Encoding 指定浏览器可以支持的web服务器返回内容压缩编码类型。 Accept-Encoding: compress, gzip
Authorization HTTP授权的授权证书 Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Cookie HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器。 Cookie: $Version=1; Skin=new;
Content-Length 请求的内容长度 Content-Length: 348
Content-Type 请求的与实体对应的MIME信息 Content-Type: application/x-www-form-urlencoded
Expect 请求的特定的服务器行为 Expect: 100-continue
From 发出请求的用户的Email From: user@email.com
Host 指定请求的服务器的域名和端口号 Host: www.zcmhi.com

4月21

接口运行结果代码乱码

a���[��
�8N���]��3�K�Eʸe�����a�;(�ĕͱ:9���JUeg�zw^
�\ϵu`:�G�ǏK�1r�<]�4�F'n� ��a��8���/�������-����?��    ��UV
a���[��
�8N���]��3�K�Eʸe�����a�;(�ĕͱ:9���JUeg�zw^
�\ϵu`:�G�ǏK�1r�<]�4�F'n� ��a��8���/�������-����?��    ��UV四月 21, 2021 8:19:03 下午 org.apache.commons.httpclient.HttpMethodBase getResponseBody
a���[��
�8N���]��3�K�Eʸe�����a�;(�ĕͱ:9���JUeg�zw^
�\ϵu`:�G�ǏK�1r�<]�4�F'n� ��a��8���/�������-����?��    ��UV

http协议,就协议本身而言,是一种文本协议。文本协议可读性比较好,但是协议所占的字节较多。目前http服务端响应普遍是json格式。其实是文本格式都行的。xml也算

java栈会接触较多的xml。而且xml的表达性更强,尤其针对字符类型

请求里的Header,Accept为标识返回协议json/xml的参数。在浏览器抓到的请求为xml但是自动化要改为Accept: application/json

长连接的保活机制:  https://blog.csdn.net/qq_22642239/article/details/109024544

解决办法:json xml反序列化转换、把xml转化为json格式

postman 浏览器之所以支持xml转json是因为工具本身支持 自动化的话需要自己封装框架

参考 Quickest way to convert XML to JSON in Java

https://stackoverflow.com/questions/1823264/quickest-way-to-convert-xml-to-json-in-java

  • 先接收接口的原始格式响应,也就是xml格式响应
  • 将xml 转为java 的对象数据类型,需要下载jar包
  • 如果还需要转换成json对象的话,再序列化一下即可,序列化也有jar包
import org.json.JSONObject;
import org.json.XML;
import org.json.JSONException;public class Main {public static int PRETTY_PRINT_INDENT_FACTOR = 4;public static String TEST_XML_STRING ="<?xml version=\"1.0\" ?><test attrib=\"moretest\">Turn this to JSON</test>";public static void main(String[] args) {try {JSONObject xmlJSONObj = XML.toJSONObject(TEST_XML_STRING);String jsonPrettyPrintString = xmlJSONObj.toString(PRETTY_PRINT_INDENT_FACTOR);System.out.println(jsonPrettyPrintString);} catch (JSONException je) {System.out.println(je.toString());}}
}

4月21

DBModel类

新增mysql8.0连接数据库 对数据库增删改查等方法封装 测试结果写入数据库

public class DBModel {/*** 本人4月新增开始!!!*/// 建立数据库连接public static Connection conn = null;public static PreparedStatement pst = null;// 创建数据库驱动:mysql之前的版本为5.1.34,driver=com.mysql.jdbc.Driver。8.0.15版本后,driver=com.mysql.cj.jdbc.Driver。多了cj
//        String driver = "com.mysql.jdbc.Driver";public static String driver = "com.mysql.cj.jdbc.Driver";//数据库IP地址public static String ip = "xx";//数据库端口public static int port = 3306;//连接的mysql的数据库名字public static String database = "xx";// mysql配置时的用户名public static String user = "root";// mysql配置时的密码public static String password = "xx";// URL指向要访问得数据库名 database
//        String url = "jdbc:mysql://" + ip + ":" + port + "/" + database + "?useUnicode=true&characterEncoding=utf8";public static String url = "jdbc:mysql://" + ip + ":" + port + "/" + database +"?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT&useSSL=false";// 加载jdbc驱动程序static {try {Class.forName("com.mysql.cj.jdbc.Driver").newInstance();} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (InstantiationException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();}}// 建立数据库连接public static Connection getConnection() {try {conn = DriverManager.getConnection(url, user, password);} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}return conn;}// 关闭数据库连接public static void closeConnection(ResultSet rst, PreparedStatement pst, Connection conn) throws Exception {try {if (rst != null) {rst.close();}if (pst != null) {pst.close();}if (conn != null) {conn.close();}} catch (Exception e) {// TODO: handle exceptione.printStackTrace();}}/*** 对应数据库字段:build_number** @param build_number* @param job_id* @return*/public static String reportAll(String build_number, String job_id, int passed, int failures, int skip, int total) {Connection conn = null;Statement st = null;boolean ret = false;try {Class.forName(driver);conn = DriverManager.getConnection(url, user, password);try {st = conn.createStatement();//                String sql = "insert into api_job (build_number) values('CMO-3.1-daily_2021-04-19 12:55:09.tar.gz');";String sql1 = "insert into api_job (build_number,job_id,passed,failures,skip,total) " +"values('" + build_number + "','" + job_id + "',"+ passed + "," + failures + "," + skip + "," + total + ");";
//            String sql = "select * from api_job where build_number=\"CMO-3.1-daily_2021-04-19 10:55:09.tar.gz\";";System.out.println("debug-sql==" + sql1);
//                System.out.println("debug-st==" + st);// 插入sql,如果插入成功则返回成功的条数,executeUpdate返回结果为int类型int issucc1 = st.executeUpdate(sql1);
//                int issucc2 = st.executeUpdate(sql2);// execute返回结果为boolean类型
//                boolean issucc = st.execute(sql);System.out.println("debug-issucc1==" + issucc1);
//                System.out.println("debug-issucc2==" + issucc2);// 以下3行conn的操作不加也行。默认AutoCommit应该是开启的,不用手动commit了。commit是为了一次执行多个SQL用的/*在connection类中提供了3个控制事务的方法:(1) setAutoCommit(Boolean autoCommit):设置是否自动提交事务(2) commit();提交事务(3) rollback();撤消事务参考博客https://www.cnblogs.com/Bonker/p/5417967.htmlinnodb锁机制: https://www.cnblogs.com/aipiaoborensheng/p/5767459.html如果一个方法里面要执行多个SQL操作,那么开始可以设置不自动提交,然后等多个SQL操作完成了,统一提交,如果出错了就回滚*/
//                conn = getConnection();
//                // auto commit 设置为false之后,就不会自动提交,会导致其他索引"锁冲突"的语句阻塞
//                conn.setAutoCommit(false);//在conn = getConnection();后面添加这么一句即可。
//                conn.commit();
//                System.out.print("sql语句执行成功");  //执行能后现实该语句,应该实执行成功了。// 正常的话 这里应该返回1if (issucc1 > 0) {ret = true;} else {ret = false;}} catch (SQLException ex) {ex.printStackTrace();}System.out.println("debug-ret==" + ret);
//            closeConnection(rs, pst, conn);} catch (Exception e) {e.printStackTrace();} finally {if (conn != null) {try {conn.close();conn = null;} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}// insert插入数据需要关闭数据连接的代码。查询需要打开
//            session.disconnect();}return null;}

同时新增logOpera的工具类

public class logOpera {public static int pass(String logname) {String filePathAll = "/Users/qa/Desktop/2021/code/APInterfaceFrame/testresult/";String countLog = filePathAll + logname;
//        System.out.println("filePath_type=="+filePath_type);String[] logs = readTxt(countLog);// 顺序:pass fail ignore totalHashMap<String, String> hm = new HashMap<>();int pass;int fail;int ignore;int total;for (int i = 0; i < logs.length; i++) {// 打印接口返回的数据
//            System.out.println("第【" + i + "】条日志,预发环境pre接口返回response为=======" + response);
//            System.out.println("每次循环的totalCount=="+totalCount);//            System.out.println("logs==" + logs[i]);hm.put("pass", logs[0]);hm.put("fail", logs[1]);hm.put("ignore", logs[2]);hm.put("total", logs[3]);
//            System.out.println("hm=="+hm);}pass = Integer.parseInt(hm.get("pass"));fail = Integer.parseInt(hm.get("fail"));ignore = Integer.parseInt(hm.get("ignore"));total = Integer.parseInt(hm.get("total"));//        System.out.println("pass==" + pass);
//        System.out.println("fail==" + fail);
//        System.out.println("jgnore==" + ignore);
//        System.out.println("total==" + total);return pass;}
 

数据库字段

package com.interfaceframe.bg.testcase;@RunWith(OverrideRunner.class)
public class mecdebug {@Test@Case(desc = "mecdebug.txt", order = 1)public void login() {long startTime = System.currentTimeMillis();String start_time = TimeTransfer.TimeStamp2Date(startTime);System.out.println("所有case开始时间==" + start_time);new CaseUtil().executeCase("/mec/mecdebug.txt", "/URL/mectest.txt");long endTime = System.currentTimeMillis();System.out.println("所以case结束时间==" + TimeTransfer.TimeStamp2Date(endTime));/***  插入build_number。在cmo设置中可以看到版本号*/String build_number = "CMO-3.1-daily_" + TimeTransfer.TimeStamp2Date() + ".tar.gz";
//        System.out.println("debug-插入build_number==" + 插入build_number);/*** 插入job_id唯一id*/String job_id = new RandomJobid().getId();
//        System.out.println("job_id==" + job_id + ",长度为==" + job_id.length());/*** 插入passed failures errors skip total 各自的用例数*/String logname = "mecdebug_login.txt";int passed = logOpera.passed(logname);System.err.println("debug-passed=" + passed);int failures = logOpera.failures(logname);System.err.println("debug-failures=" + failures);int errors = 0;System.err.println("debug-errors=" + errors);int skip = logOpera.skip(logname);System.err.println("debug-skip=" + skip);int total = logOpera.total(logname);System.err.println("debug-total=" + total);/*** 插入duration_time case运行时长*/float duration_time = endTime - startTime;System.err.println("debug-duration_time=" + duration_time);/*** 整体插入,调用封装的数据库方法*/DBModel.reportAll(build_number, job_id, passed, failures, errors, skip, total, duration_time, start_time);}}

效果:testng自动化运行结果插入mysql数据库成功,耶!!!

完整记录如下


新增Utils工具类下的RandomJobid

package com.interfaceframe.bg.util;import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;public class RandomJobid {public String getId() {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");long time = new Long(System.currentTimeMillis()); // 获取当前时间的unix时间戳// 截取前10位 2021-04-20 11:44:34String format = sdf.format(new Date(time)).substring(0, 10).replaceAll("-", "");// 打印为8位数字
//        System.out.println("format==" + format);UUID uuid = UUID.randomUUID();// 32位的唯一id拼接8位时间,最终返回40位的jobidString jobId = uuid.toString().replace("-", "") + format;return jobId;}public static void main(String[] args) {for (int i = 1; i <= 10; i++) {System.out.println("第" + i + "次循环: " + new RandomJobid().getId() + ",长度是:" + new RandomJobid().getId().length());}//第1次循环:d93d954031ba46f189218b70fb515e81}
}

CaseUtil类executeCase方法

记录pass fail ignore total的数目,插入数据库用

private String log;
private String logCount;
        log = "testresult/" + genedReportName + "_Result.log"; // 获得调用者的方法名logCount = "testresult/" + genedReportName + "Log_log"; // 获得调用者的方法名// 4月8开会讨论保留历史日志,加时间戳
//        log = "testresult/" + TimeTransfer.TimeStamp2Date(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss") + "_" + genedReportName + "_Result.log";//FileUitl.deleteFile(log);FileUitl.deleteFile(logCount);
//记录每个case的log日志
StringBuffer caseStepLog = new StringBuffer();
StringBuffer caseStepLogCount = new StringBuffer();
// 4月新增
int total = pass + fail + ignore;
System.err.println("pass=【" + pass + "】,fail=【" + fail + "】,ignore=【" + ignore + "】,total=【" + total + "】");caseStepLogCount.append("pass=" + pass + ",fail=" + fail + ",ignore=" + ignore + ",total=" + total); //测试通过
FileUitl.writeFile(logCount, caseStepLogCount.toString());

4月19

如遇

com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Could not create connection to database server.

完整日志

com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Could not create connection to database server.
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:377)
    at com.mysql.jdbc.Util.getInstance(Util.java:360)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:935)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:924)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:870)

解决办法:参考https://blog.csdn.net/zht741322694/article/details/82464024

原框架里的mysql jar包版本是5.1.34 要下载8.0版本的

参考mysql 8.0.15 jar包下载地址/mysql8.0jar包下载地址(mysql官网下载https://jingyan.baidu.com/article/22fe7ced29711e3002617f2c.html)

或者  https://dev.mysql.com/downloads/file/?id=484819

直接点击No thanks, just start my download. 下载包将直接以zip格式下载到本地,解压就看到了

下载完8.0.15jar包,在project structure-Modules-Dependencies-libss(原来的放到这里了)-点击+导入下载的jar包(放到项目目录的lib-/Users/qa/Desktop/2021/code/APInterfaceFrame/libss,再从这里导入加载。单纯的拷贝到libs下面不会生成META-INFO和org文件)

加载完成,jar包可以正常展示了。可以展开了


继续执行报错

Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.

如遇

Sun Apr 18 22:29:27 CST 2021 WARN: Caught while disconnecting...

EXCEPTION STACK TRACE:

** BEGIN NESTED EXCEPTION **

javax.net.ssl.SSLException
MESSAGE: closing inbound before receiving peer's close_notify

STACKTRACE:

javax.net.ssl.SSLException: closing inbound before receiving peer's close_notify
    at sun.security.ssl.Alert.createSSLException(Alert.java:133)
    at com.interfaceframe.bg.jdbc.mysql.util.DBUtil.main(DBUtil.java:74)

** END NESTED EXCEPTION **

解决办法:参考博客https://blog.csdn.net/qq_34075488/article/details/85106860

在使用spring boot整合jpa时出现上述错误,去网上找了很多资料,按照所述方法试了之后仍报错,但最后发现了一篇文章。在配置文件中,配置连接数据库的url时,加上useSSL=false。如以下格式,注意将数据库名(db_testjpa)改为你自己的数据库名。

spring.datasource.url = jdbc:mysql://localhost:3306/db_testjpa?serverTimezone=GMT%2B8&useSSL=false

修改DBUtil类,getConn()方法

参考博客https://blog.csdn.net/weixin_47962780/article/details/106980730  mysql8.0新版本的mysql连接代码、mysql8.0 jdbc连接代码_Mysql8.0的JDBC连接配置

    public static Connection getConn() {Connection conn = null;// 创建数据库驱动:mysql之前的版本为5.1.34,driver=com.mysql.jdbc.Driver。8.0.15版本后,driver=com.mysql.cj.jdbc.Driver。多了cj
//        String driver = "com.mysql.jdbc.Driver";String driver = "com.mysql.cj.jdbc.Driver";//数据库IP地址String ip = "xx.xx.xx.xx";//数据库端口int port = 3306;//连接的mysql的数据库名字String database = "database";// mysql配置时的用户名String user = "root";// mysql配置时的密码String password = "passwd";// URL指向要访问得数据库名 database
//        String url = "jdbc:mysql://" + ip + ":" + port + "/" + database + "?useUnicode=true&characterEncoding=utf8";String url = "jdbc:mysql://" + ip + ":" + port + "/" + database +"?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT&useSSL=false";// 不加useSSL=false会报错javax.net.ssl.SSLException MESSAGE: closing inbound before receiving peer's close_notify
//                "?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT";try {Class.forName(driver);// 百度出来的结果:需要增加&useSSL=false,参考博客https://blog.csdn.net/qq_34075488/article/details/85106860conn = DriverManager.getConnection(url, user, password);System.out.println("conn==" + conn);
//            conn = DriverManager.getConnection(url, user, password);} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}return conn;}

4月16

CaseUtil类

新增对传参格式的转换 之前为String类型,转化为map方式解析,供get方法调用

Line233-247

                    // 4月16新增把传参String类型转化为map 原来的框架不支持application/text格式的传参 仅支持applicationjson/json类型result = Get.get("get", CombinationGetUrl, getParama(paramContent)); //执行get方法 转换为map
//                            result = Get.get("get", CombinationGetUrl, paramContent); //执行get方法 原有的框架仅支持String类型} else {//System.out.println("未加密后的get Url: "+CombinationGetUrl);
//                    result = Post.post("get", inteface_url[1], paramContent); //执行get方法result = Get.get("get", inteface_url[1], getParama(paramContent)); //执行get方法 原有的框架仅支持String类型System.out.println("");}
// 4月16新增把传参String类型转化为map 原来的框架不支持application/text格式的传参 仅支持applicationjson/json类型
// 之前自己写的httpclient框架支持2种类型
public HashMap<String, String> getParama(String paramContent) {HashMap<String, String> map = new HashMap<>();if (!TextUtils.isEmpty(paramContent)) {String[] arrayParam = paramContent.split("&");for (int n = 0; n < arrayParam.length; n++) {int index = arrayParam[n].indexOf("=");String key = arrayParam[n].substring(0, index);String valuue = arrayParam[n].substring(index + 1);map.put(key, valuue);}}return map;
}
// 4月16为了兼容自动化运行结果以英文展示写到数据库,框架casename_Chinese = caseFields[0].trim(); // 第1行,中文测试用例名称,如登录cmo系统,此值不取,忽略此行,注释casename = caseFields[1].trim(); // 第2行,英文测试用例名称,如login cmo system,自动化取此行interfaceName = caseFields[2].trim(); // loginmethod = caseFields[3].trim();paramContent = caseFields[4].trim();if (method.contains("get")) {check = Integer.parseInt(caseFields[5].trim());if (caseFields.length == 7) {expectResultString = caseFields[6].trim();//System.out.println("get's expectResultString>>>> "+expectResultString);} else {expectResultString = null;}}

4月13

JSONUtil类

新增返回的value为int类型时,如果自动化case接口结果写null,则只校验key不校验value值

新增返回的value为String类型时,如果自动化case接口结果写"",则只校验key不校验value值

Line177-181

{
 "page_num": 1,
 "page_size": 10,
 "total": null,    //只校验key不校验value值 
 "data": [{
  "datacenter_id": "",   //只校验key不校验value值 
  "datacenter_name": "mec-49-0412",
  "register_status": 4,
  "is_connect": true
 }]
}

    // 4月12新增返回的value为int类型时,如果自动化case写null,则只校验key不校验value值
} else if (value == null) {if (actualResultMap.get(key) == null) {System.out.println(key + " 和期望结果的 " + key + "相等!具体返回值请参阅下面:");System.out.println("系统返回的结果为 " + key + "=" + actualResultMap.get(key) + "\n"+ "期望的返回结果为 " + key + "=" + value + "\n");} else {++fail;System.err.println(key + " 和1期望结果的 " + key + "不相等!具体差异请看下面:*************************请注意");String errorlog = "系统返回的结果为 " + key + "=" + actualResultMap.get(key) + "\\n"+ "期望的返回结果为 " + key + "=" + expectResultMap.get(key) + "\\n";System.err.println(errorlog.replaceAll("\\\\n", "\n"));Wait.time(100);sb.append(errorlog + "\\n");isPass = false;}} else {//System.out.println(testResultMap.get(key)+" ? "+expectResultMap.get(key).toString().trim());// 4月13新增返回的value为String类型时,,如果自动化case写"",则只校验key不校验value值if (TextUtils.isEmpty(expectResultMap.get(key).toString().trim())|| actualResultMap.get(key).toString().trim().equals(expectResultMap.get(key).toString().trim())) {System.out.println(key + " 和期望结果的 " + key + "相等!具体返回值请参阅下面:");System.out.println("系统返回的结果为 " + key + "=" + actualResultMap.get(key) + "\r\n"+ "期望的返回结果为 " + key + "=" + expectResultMap.get(key) + "\n");} else {


4月13

Get类

Line38-132

get请求 此方法均支持text json格式的请求。4月13日新增支持Content-Type为text/html格式
为啥新增?因为原来的框架不支持Content-Type text/html; charset=UTF-8(图上面的那张)。。。只支持Content-Type application/json; charset=utf-8

// 优化前的框架调用这里
public class Get {public static String get(String method, String url, String paramter) {if (method == null || "".equals(method) || url == null || "".equals(url)) {return Var.message1;}if (Var.get.equals(method)) {if (paramter == null || "".equals(paramter)) {return HttpXmlClient.get(url);} else {return HttpXmlClient.get(url, paramter);}} else if (Var.post.equals(method)) {return HttpXmlClient.postJsonStr(url, paramter);}return Var.message2;}/*** get 请求,只需将变动的参数传入params中即可** @param url* @param params* @return*/public static String requestURL;// 优化后的框架调用这里// get请求 此方法均支持text json格式的请求。4月13日新增// 为啥新增?因为原来的框架不支持Content-Type text/html; charset=UTF-8。。。只支持Content-Type application/json; charset=utf-8public static String get(String method, String url, Map<String, String> paramter) {try {Header header = new Header("Content-type", "application/json");String response = "";// HttpClient是Apache Jakarta Common下的子项目,用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包,并且它支持HTTP协议最新的版本和建议。// HttpClient已经应用在很多的项目中,比如Apache Jakarta上很著名的另外两个开源项目Cactus和HTMLUnit都使用了HttpClient。// 使用HttpClient发送请求、接收响应HttpClient httpClient = new HttpClient();if (url != null) {// NameValuePair是简单名称值对节点类型。多用于Java像url发送Post请求。在发送post请求时用该list来存放参数
//                getParamsList(url_online, params, count);// 预发环境value替换线上环境valueList<NameValuePair> qparams_pre = getParamsList_pre(paramter);if (qparams_pre != null && qparams_pre.size() > 0) {String formatParams = EncodingUtil.formUrlEncode(qparams_pre.toArray(new NameValuePair[qparams_pre.size()]),"utf-8");
//                    url = url.indexOf("?") < 0 ? url + "?" + formatParams : url + "&" + formatParams;url = url.indexOf("?") < 0 ? url + "?" + formatParams : url + formatParams;}requestURL = url;System.out.println("日志,预发环境pre请求的url==" + url);GetMethod getMethod = new GetMethod(url);getMethod.addRequestHeader(header);/*if (null != headers) {Iterator var8 = headers.entrySet().iterator();while (var8.hasNext()) {Map.Entry<String, String> entry = (Map.Entry)var8.next();getMethod.addRequestHeader((String)entry.getKey(), (String)entry.getValue());}}*///System.out.println(getMethod.getRequestHeader("User-Agent"));int statusCode = httpClient.executeMethod(getMethod);// 如果请求失败则打印出失败的返回码if (statusCode != 200) {System.out.println("第" + statusCode + "日志,预发环境请求出错,错误码为=======" + statusCode);return response;}response = new String(getMethod.getResponseBody(), "utf-8");}return response;} catch (Exception e) {e.printStackTrace();}return null;}// 参数格式化private static List<NameValuePair> getParamsList_pre(Map<String, String> paramsMap) {if (paramsMap != null && paramsMap.size() != 0) {List<NameValuePair> params = new ArrayList();Iterator var2 = paramsMap.entrySet().iterator();while (var2.hasNext()) {Map.Entry<String, String> map = (Map.Entry) var2.next();// 预发环境最新版本日志回放,请求参数打开以下if else,注释掉最后一行// 参数格式化,commons-httpclient自带的方法NameValuePair会自动将==转为=,还有特殊符号格式化// NameValuePair是简单名称值对节点类型。多用于Java像url_test发送Post请求。在发送post请求时用该list来存放参数params.add(new NameValuePair(map.getKey() + "", map.getValue() + ""));//                params.add(new NameValuePair(map.getKey() + "", map.getValue() + ""));}return params;} else {return null;}}
}


4月9

CaseUtil类

Line58-66

昨天开会大家提出的建议保留历史log和report 对框架作出调整 如下

        String genedReportName = getExecuteCaseClassName(stackTraceElement.getClassName()) + "_" + stackTraceElement.getMethodName();//        log = "testresult/" + stackTraceElement.getClassName() + "_" + stackTraceElement.getMethodName() + "_Result.log"; // 获得调用者的方法名// 4月8开会提出的建议,保留历史日志信息,改为追加日期保存log = "testresult/" + TimeTransfer.TimeStamp2Date(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss") + "_" + genedReportName + "_Result.log";// 获得调用者的方法名// 删除原日志FileUitl.deleteFile(log);//        String writetoHtml = "testresultHtml/" + genedHtmlName + ".html";// 4月8开会提出的建议,保留历史报告信息,改为追加日期保存String writetoHtml = "testresultHtml/" + TimeTransfer.TimeStamp2Date(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss") + "_" + genedReportName + ".html";ReportUtil report = new ReportUtil(writetoHtml);

新增时间戳转换工具类

package com.interfaceframe.bg.util;import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;public class TimeTransfer {/*** Java将Unix时间戳转换成指定格式日期字符串** @param timestampString 时间戳 如:"1616410206";* @param formats         要格式化的格式 默认:"yyyy-MM-dd HH:mm:ss";* @return 返回结果 如:"2021-03-22 18:50:06";*/public static String TimeStamp2Date(long timestampString, String formats) {Long timestamp = timestampString;String date = new SimpleDateFormat(formats, Locale.CHINA).format(new Date(timestamp));return date;}}


4月8

HttpXmlClient类

Line74-121

发现的问题,实际返回结果一直在变。这种的正常(虚拟机 磁盘 内存 amount ioread iowrite cpu等),只需要校验key  value不校验,改为null

huge_pages 和期望结果的 huge_pages不相等!具体差异请看下面:*************************请注意
系统返回的结果为 huge_pages="[HugePage:{sizeKB='1048576', amount='58'}]"
期望的返回结果为 huge_pages="[HugePage:{sizeKB='1048576', amount='98'}]"

debug模式下发现正常的get有参数的请求无法走到下面的方法,原因:原有的框架没有get方法,只支持post方法

// get请求有参数方法
public static String get(String url, String paramter) {CloseableHttpClient httpclient = HttpClients.createDefault();String body = null;System.err.println("GET URL:" + url + paramter);

基于框架调整,新增get方法

package com.interfaceframe.bg.method;import com.interfaceframe.bg.util.HttpXmlClient;
import com.interfaceframe.bg.var.Var;public class Get {public static String get(String method,String url, String paramter) {if (method==null || "".equals(method) || url==null || "".equals(url)){return Var.message1;}if (Var.get.equals(method)){if (paramter==null||"".equals(paramter)){return HttpXmlClient.get(url);}else{return HttpXmlClient.get(url , paramter);}}else if (Var.post.equals(method)){return HttpXmlClient.postJsonStr(url, paramter);}return Var.message2;}
}


4月6

HttpClient的get post请求参数中带有特殊字符响应400问题

参考博客  https://blog.csdn.net/zhang_m_h/article/details/108882194

分析接口自动化运行结果,发现response status(Response Code)为400 正常为200

分析了半天,请求在浏览器postman均正常返回,最后发现是传的参数有问题,

||mec_id=7492d6db-2778-418d-83a2-746e109172c8&page=1&pageSize=10&sort=boot_time

mec_id的value中含有特殊参数-

解决办法:优化框架。对get post请求参数解析时增加URLEncode

4月1 4月8又修改了下

JSONUtil类

Line27-44

序列号:4 cmo获取mec集群列表,正常返回,返回的datacenterid为uuid->4

报错分析,接口返参奇怪的为数组格式--一般公司不这样返回。。。

[{
    "CMOID": "xx",
    "DatacenterID": "xx",
    "DatacenterName": "xx",
    "RegisterStatus": 4,
    "Version": 0,
    "UpdateTime": "2021-03-29 17:59:11 CST",
    "CreateTime": "2021-03-28 08:28:28 CST",
    "Comment": ""
}]

针对特殊的格式优化框架

    public static Map<String, Object> parseJSON2Map(String jsonStr) {/*jsonStr = jsonStr.replaceAll("\n", "").replaceAll("\t", "").replaceAll(" ", "");*///        System.out.println("接口返回的原始json parseJSON2Map---->" + jsonStr);ListOrderedMap map = new ListOrderedMap();// 2021.4.新增// json数组解析(用数组的比较少,不知道这边RD为啥选取这种格式,百度阿里没见过这种返回)// 如果最外层的json为Object数组,则需要去掉json前后的[]为标准的json再去解析,左开右闭,从1开始算if (jsonStr.startsWith("[")) {jsonStr  = jsonStr.substring(1, jsonStr.length() - 1);System.out.println("重新解析后的jsonnew==" + jsonStr);JSONObject json = JSONObject.fromObject(jsonStr);System.out.println("json==" + json);// 再对json最外层解析for (Object k : json.keySet()) {Object v = json.get(k);map.put(k.toString(), v);}// 标准的json返回格式为{}或者{[{},{}]}} else {// json最外层解析JSONObject json = JSONObject.fromObject(jsonStr);for (Object k : json.keySet()) {Object v = json.get(k);map.put(k.toString(), v);}}return map;}

运行结果如下,期望值和实际值打印出来了,4月1调整的框架忘了遍历json,只是转换了json格式。。。嘻嘻

如遇401错误,接口header缺少参数

HttpXmlClient类

Line59-67

IntelliJ IDEA引入第三方jar包或查看Java源码的时候报decompiled.class file bytecode version:52.0(java 8)错误的解决办法

解决办法:在oracle官网下载最新的jdk 安装

链接如下

https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html

修改本地配置文件

cd ~

vim .bash_profile

➜  ~ git:(master) ✗ /usr/libexec/java_home

/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home

➜  ~ git:(master) ✗ echo $JAVA_HOME

/Library/Java/JavaVirtualMachines/jdk1.8.0_281.jdk/Contents/Home

java -version

修改idea的配置 Project Structure-Platform Settings-SDK

和Preference-Maven-Importing

之前为1.8.0.101 最新的macOS版本为1.8.0.281,把JAVA_HOME的路径写到这里

.class文件这个是反编译出来的文件,提示一下这是在jdk8环境编译的 提示意义 可以忽略。.class文件是编译好的 .java的可以编辑。.class是编译后的文件。类似于.exe文件,可以运行的文件。需要编辑源码不是编辑编译后的文件。其实算是看错文件了,我的错。。。。



3月25

HttpXmlClient类

Line102-115

httpget封装

public static String get(String url) { 
    CloseableHttpClient httpclient = HttpClients.createDefault();

String body = null;   
    System.out.println(url); 
    HttpGet get = new HttpGet(url);
    // header头部封装 根据公司现在的传参结构,需要把token认证放到header。2021年3月25调整
    get.addHeader("Content-type", "application/json; charset=utf-8");
    get.addHeader("X-Auth-Token", "xxtoken");

body = invoke(httpclient, get);        
    closeHttpClient(httpclient);
    return body.trim(); 
}



3月24

遇到的问题及解决

1. eclipse本身支持junit,macOS升级11.2.1版本bigsur后,eclipse不能安装,提示Failed to create the Java Vitual Machine 参考若干博客无解,原因:Info.plist系统设置为644 无法sudo改为777

https://blog.csdn.net/lizhen5117/article/details/109680225

2.下载testng的依赖包maven仓库

地址 search.maven.org

https://search.maven.org/search?q=a:testng

testng的pom配置正常,但是依赖没下载下来。。。scope这里有的博客是test 有的是compile 但是都不对,监听器无法正常继承--待解决

import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.TestListenerAdapter;

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>provided</scope>
</dependency>

3. 改用jar包方式,发现

运行单元测试用例的时候报错了,java.lang.NoClassDefFoundError: org/hamcrest/SelfDescribing

现在有两个办法解决:

junit版本降到4.10    免费下载地址  http://www.java2s.com/Code/Jar/j/Downloadjunit410jar.htm

或者导入hamcrest-core-1.3.jar   免费下载地址 http://www.java2s.com/Code/Jar/h/Downloadhamcrestcore13jar.htm

网上99.9%的搜索结果都是收费的  提供免费地址  http://www.java2s.com/Code/Jar/h/

参考博客  https://blog.csdn.net/u011954243/article/details/77962329

下载完jar包,在project structure-Modules-Dependencies-libs-点击+导入下载的jar包(放到项目目录的lib-/Users/qa/Desktop/2021/code/APInterfaceFrame/libs,再从这里导入加载。单纯的拷贝到libs下面不会生成META-INFO和org文件)

终于OK了

待续。。。

httpclient+testng接口自动化框架二次封装Java相关推荐

  1. python小工具封装_python接口自动化(二)——封装需要用到的工具类

    封装需要用的工具类: 1.封装读取Excel的工具类,这里选用的是pandas: importpandas as pd path= 'test.xlsx'sheet_name= 'test_data' ...

  2. python api开发用什么框架_python+requests接口自动化框架

    为什么要做接口自动化框架 1.业务与配置的分离 2.数据与程序的分离:数据的变更不影响程序 3.有日志功能,实现无人值守 4.自动发送测试报告 5.不懂编程的测试人员也可以进行测试 正常接口测试的流程 ...

  3. python 自动化框架打包_python+requests接口自动化框架

    为什么要做接口自动化框架 1.业务与配置的分离 2.数据与程序的分离:数据的变更不影响程序 3.有日志功能,实现无人值守 4.自动发送测试报告 5.不懂编程的测试人员也可以进行测试 正常接口测试的流程 ...

  4. python+requests+pytest 接口自动化框架(一)

    目录 一.Pytest详解以及常用的插件安装 二.Pytest默认的测试用例的规则 三.Pytest用例运行方式以及参数 1.命令行模式运行 命令:pytes 2.主函数模式运行 3.基于pytest ...

  5. python接口自动化实战(框架)_python接口自动化框架实战

    python接口测试的原理,就不解释了,百度一大堆. 先看目录,可能这个框架比较简单,但是麻雀虽小五脏俱全. 各个文件夹下的文件如下: 一.理清思路 我这个自动化框架要实现什么 1.从excel里面提 ...

  6. pytest+yaml设计接口自动化框架过程记录(一步一步记录如何设计,完结撒花),源码提供,视频教程

    pytest+yaml设计接口自动化框架过程记录 第三代框架使用教程,该框架比现在这个完善了很多 框架简介 框架运行演示和功能介绍视频 pytest+yaml框架环境配置和使用教程 0.去年也写了一个 ...

  7. Python语言+pytest框架+allure报告+log日志+yaml文件+mysql断言实现接口自动化框架

    目录 前言 实现功能 目录结构 依赖库 安装教程 接口文档 如何创建用例 创建用例步骤 用例中相关字段的介绍 如何发送get请求 如何发送post请求 如何测试上传文件接口 上传文件接口,即需要上传文 ...

  8. 接口自动化 ------ 快速搭建接口自动化框架

    接口自动化框架要搭成什么,里面的内容究竟应该有多少? 这个问题没有标准答案,因为这要取决于你的项目,以及你想要用框架来解决什么问题等多种因素. 当然了,这里也就不展开讨论了,还是回到接口自动化这个点, ...

  9. 浅谈python+requests接口自动化框架

    为什么要做接口自动化框架 1.业务与配置的分离 2.数据与程序的分离:数据的变更不影响程序 3.有日志功能,实现无人值守 4.自动发送测试报告 5.不懂编程的测试人员也可以进行测试 正常接口测试的流程 ...

最新文章

  1. 微信浏览器跳转页面加载loading效果问题
  2. c语言英汉互译编程,用C语言编辑简单英汉互译词典.doc
  3. iOS多线程编程:线程同步总结 NSCondtion
  4. vue-router思维导图
  5. 启用了不安全的HTTP方法
  6. php文件里搜索关键字,php - PHP从文本文件中搜索关键字(Action'),使用该关键字打印所有行,然后计算打印的行数 - SO中文参考 - www.soinside.com...
  7. 揭秘“21世纪最性感的职业”:数学、编程、沟通和商业技能一个都不能少!...
  8. 30 FI配置-财务会计-外币评估-准备外币评估的自动过账
  9. Kafka eagle 安装
  10. RazorSQL for Mac:查看和编辑二进制数据和图像
  11. 宝马发布三款新车,2019年将开启最大规模产品攻势...
  12. OpenCv图像像素操作
  13. PSpice和Simulink联合仿真笔记(一)SLPS介绍
  14. Linux系统编程---消息队列
  15. 金沙滩开发板单片机学习笔记(2)
  16. shareSdk 新浪微博的登录分享测试
  17. 2022国产芯片技术创新与市场应用论坛即将召开
  18. 托福高频真词List10 // 附托福TPO阅读真题
  19. PAT B1033旧键盘打字
  20. [nRF51822] 1、一个简单的nRF51822驱动的天马4线SPI-1.77寸LCD彩屏DEMO

热门文章

  1. Halcon3d 点云计算平面度
  2. Ai如何使用路径快速制作圆点从大到小效果,有什么好的方法吗
  3. ZZY.QR 简单二维码生成编辑器
  4. iOS中UITextField的使用
  5. 亲测可用!Ubuntu 上PAC VOC数据集划分Python代码实现!
  6. 数据结构(六)——循环链表
  7. Broadcast 探究
  8. python怎么下载pil库_如何在windows下安装Python的PIL库
  9. 【CVPR】Calibrated RGB-D Salient Object Detection
  10. 米拓+php.ini_php.ini 配置详细选项