2023年3月

一、
loadrunner  简称 LR

二、 Jmeter

1、安装包:apache-jmeter-4.0.tgz   解压。学会此工具的使用  和POSTman 一样的。

2、本机测试:双击apache-jmeter-4.0\bin 的 jmeter.bat 启动

添加线程组,后 添加两个东西,设定IP 和端口,headerManager貌似不用设定

添加 Sampler HTTP Request

添加View Results Tree ,  启动,通过View Results Tree  查看结果

拓展 ======================================

postman+jmeter接口实例 - 笨笨的妞 - 博客园--这篇对postman讲得非常好。
http://www.cnblogs.com/alasijia/p/8037094.html

postman和jmeter的接口测试案例 - 响马_800 - 博客园--也不错
http://www.cnblogs.com/zgw-800/p/8032168.html

postman中 form-data、x-www-form-urlencoded、raw、binary的区别 - 海蓝steven - 博客园
https://www.cnblogs.com/rogge7/p/8521301.html

转:有postman和Jmeter了为什么还要写接口测试框架?

学接口自动化之前我想过这个问题,之前还在群里问过这个愚蠢的问题,后来被群友喷死了,想想当时的自己也是可爱。

今天呢,看了虫师的书,聚的书中有点观点很是赞同,所以特此记录一下,也给看到博客的有缘人答疑一下啊,哈哈!

主要原因如下:

1.测试工具有很多不足的地方,比如测试数据的不可控。

接口测试的本质就是调用接口输入数据,再验证接口返回的数据是否符合预期,如果返回的数据不可控那么工具就无法断言结      果!

2.工具无法测试加密的接口,比如说一个接口的入参需要签名验证,即是对当前的时间戳+密钥进行MD5加密后传输,因为时间戳是动态的,所以一般的接口测试工具是无法模拟的

3.工具的扩展能力不足,比如想生成不同格式的测试报告,并将测试报告发送至邮箱,又或者想将接口测试集成到持续集成中,如jekins都存在局限性

综上所述:用代码的方式执行接口测试才是万能的啊!!!!!!

结束!

=====别人的评论

jmeter elk grafana influxdb 这些工具才是行业最主流的 主流的互联网公司基本都在使用这套架构

接触不到底层的是jmtet, LR都是基于传输层写代码的 这还不够底层?

LR 支持 linux

LR学习成本相对较高,但是结果分析方面jmeter是不能比的
Jmeter扩展性较好,开发插件方便(比如一些私有协议需要测试),至于报告不好看,这个完全可以自己定制(InfluxDB+grafana+Jmeter的BackEndListenser)
个人见解:工具无分好坏,适合自己的场景能达到测试目的即是好工具

jmeter操作起来比LR要“敏捷”很多

excel如何快速统计一列中相同数值出现的个数_百度经验 --这里介绍了两种解决方式,用第一种
https://jingyan.baidu.com/article/9113f81b2c16822b3214c785.html

EXCEL中怎样统计一列中重复项的个数?_百度知道--这个看起来更明了  -数据透视表
https://zhidao.baidu.com/question/241045717.html

统计后,还可以对 值进一步   筛选范围

将数据拷贝 出来。

A表  基础信息表

B表 业务信息表

将a表中的基础数据 拼接到B表的后面,

应用场景是:

B表很多数据,很繁乱,名字不一定全,

A表也是比较多的行,B表乱:比如有8行有李晨的,却只有3行是范仲淹的,现在需要快速拼接:

方法一:不用函数,利用ctrl+Enter

xls表格 ctrl+D 和ctrl+Enter区别 --快速填充相同数据,同时填充多个不同数据 - 海蓝steven - 博客园
https://www.cnblogs.com/rogge7/p/8075115.html  --利用这博文介绍

两个表的数据合并放在一个表

B 列当做姓名,C D 列当做B表的学科和分数。E F G列 当做A基础信息列。

A表复制过来的时候,要空出列,以便后面的数据可以接上B表的后面。【总的任务就是快速自动填 EFG列】

还有一点,两个表前面要加上一列 标志列。如上图A表的左边加上A标志服,B表的左边随便加点标志。

对B列进行排序,发现要向上填充数据,不太符合本实践要求。

改进:全选所有列,自定义排序:对E列做次排序

变成

按照博文说的,选择列,Ctrl+G 定位 选择 空值  在编辑栏中输入=上一个格子的地址,( 是上一个值的格子) 再按CTRL+Enter完成填充

这样就会自动往下填充了,整列完成,瞬间完成(我的几万行数据)。同时对多列是否可以操作,还没有试(后来试了,不可以)。

最后一步:把基础A表的数据删除:先将整个表的复制,到另一个新表格 粘贴为数值(不要带格式的)

对表的A列排序,把A列中有A字符的行全部删除(这是A表的基础数据),完成。

方法二:用函数 VLOOKUP

复制excel指定内容到另一个表格     -- 开工前先看此例子
https://www.kafan.cn/A/enoj498kvw.html

VLOOKUP(参数1,参数2,参数3,参数4)

=VLOOKUP(要查找的值、要在其中查找值的区域、区域中包含返回值的列号、精确匹配或近似匹配 – 指定为 0/FALSE 或 1/TRUE)。
参数2中数据区域,区域的第一列就是要查找的列,区域后面列是要返回的列,

在D1中输入公式回车,快速下拉填完整列的公式

发现有些数据找不到,明明在数据表 里面的。【奇怪的是,同一台车,有些行可以找到,有些行找不到,有空格?】

下面网上的说法:

原因有以下几个方面:1.字符串后面有空格。2.数据类型不匹配。虽然有些数字看起来都是一样的,但有的是数值型的,有的是文本型的,这二者是匹配不到一起的。3.有重复的数据。VLOOKUP只能查找到第一个数据,后面的重复数据是查找不到的。

但我数据没有空格,数值类型应该都是一样的,我觉得第3点 网友说得不对。

我仔细分析,发现我写的是: =VLOOKUP(A1,车辆列表基础信息!B2:E1575,2,0)  猜想是区域数据,没有绝对引用造成的。

点击参数2 ,按F4 绝对引用。变成:=VLOOKUP(A1,车辆列表基础信息!$B$2:$E$1575,2,0)  问题解决。

-- 后来发现
,函数用第一种写法,的第四个参数 把0改成1 模糊查找,也可以找出值来。

--拓展:VLOOKUP 是纵向查找, HLOOKUP 横行查找。 微软的excel ,点击函数帮助的时候,会跳转到此函数的中文教学视频。而wps没有教学视频。

方法三:利用宏,

wps需要安装 vbs模块, 微软自带的宏默认是禁止的,需要启动。

本人网上下载的是
vba提取自WPS2012专业增强版
,解压,点击 vba6chs.msi 安装,重启wps,打开有宏的xls,启用宏。

下载地址:http://dl.pconline.com.cn/download/470217.html

开发工具--查看代码-- 会跳转到VB编辑器

准备数据:本人将A表复制在B表的 尾端,如下截图

1到2106是
业务表
的, 2110到 3683行是
基础信息表
的, (车牌字段唯一),写了个宏,超级简单就是两个for循环。代码如下:

意思:根据业务表的车牌去 基础数据表中找到这个车牌所在行并且把后面的的基础数据复制回来放到业务表对应车牌的后面。

SubMacro1()'
'
Macro1 Macro'宏由 CLP 录制,时间: 2018/08/22' Dim x As Integer Dim Y As Integer For x = 1 To 2106 Step 1 '外层循环 循环B表所有车牌号码 For Y = 2110 To 3683 Step 1 '循环A表所有车牌号码 If Range("a" & x).Value = Range("a" & Y).Value Then 'B表查询A表的值 Range("B" & Y & ":" & "D" & Y).Select '选择区域 Selection.Copy '复制 Range("D" & x).Select '选择 ActiveSheet.Paste '粘贴 Exit For '退出内层循环 End If NextYNextxEnd Sub

执行一下 ,蛮久的(1分多钟),完成了。

==待续...

正则表达式30分钟入门教程 --很不错值得看,循序渐进的,诱敌深入,渐入佳境/美景
http://deerchao.net/tutorials/regex/regex-1.htm

正则表达式30分钟入门教程-BeJSON.com-- 这篇看着更好的样子
http://www.bejson.com/knownjson/regexJiaocheng/

----------------------

1.元字符介绍
"^" :匹配行或者字符串的起始位置
"$" :匹配行或字符串的结尾
"\w":匹配字母,数字,下划线.
"\d" : 匹配数字
"." :匹配除了换行符以外的任何字符
"[abc]": 匹配包含括号内元素的字符
2.反义
"\W" :匹配任意不是字母,数字,下划线 的字符
"\S" :匹配任意不是空白符的字符
"\D" :匹配任意非数字的字符
"\B" :匹配不是单词开头或结束的位置
"[^abc]" :匹配除了abc以外的任意字符
3.量词
"*" :重复零次或更多
"+" :重复一次或更多次
"?" :重复零次或一次
"{n,m}" :重复n到m次
"{n}" :重复n次
"{n,}" :重复n次或更多次
4限定符
"*?" :重复任意次,但尽可能少重复
"+?" :重复1次或更多次,但尽可能少重复
"??" :重复0次或1次,但尽可能少重复
"{n,m}?" :重复n到m次,但尽可能少重复
"{n,}?" :重复n次以上,但尽可能少重复

------------ 找一些  字符串 到这个网站测试一下,

在线正则表达式测试
http://tool.oschina.net/regex/#

--个人实践--


\beos\.\w*\b 可以帅选出所有 eos.开头的

\b\w*.com 筛选出,com结尾的字符串,但是前面有两个点的筛选不出来。
\b\w*\.com 查找 .com 结尾的
\b\w*\.\w*\.com 只有两个点的.com结尾的被筛选出来
\b\w*\.\w*\.com|\b\w*\.com 一个点或两个点都被筛选出来。
\bvip\.\w*\b 筛选vip. 开头的

\b.*vip.*\b 包含vip的都会出来

\b.*[1-5]{1,12}.*\b 包含1到5数字的都出来


(\d{1,3}\.){3}\d{1,3} 匹配ip,但它也将匹配256.300.888.999这种 错误ip
正确的IP地址:((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)。
理解这个表达式的关键是理解2[0-4]\d|25[0-5]|[01]?\d\d?,
2[0-4]\d|25[0-5]|[01]?\d\d? 第一种2开头中间是0到4后面一个随意;第二种25开头,后面一位小于6;
第三种第一位0或1出现一次或者零次,第二位任意数字,第三位数字出现一次或者0次。

验证手机号码 实际代码中 ^[1][3,4,5,7,8][0-9]{9}$这样用,^$整个字符串中,1开头,第二位34578中一个,后接9位数字

--网络例子实践

正则小应用:批量修改文件名   ---里面有点代码
https://zhuanlan.zhihu.com/p/41655899

if (/(\d+\.jpg)/.test(v)) {
fs.rename(v,
'baluobo' + RegExp.$1.padStart(6, '0'), () =>{})
}

这个正则 /(\d+\.jpg)/  这个正则会将 .jpg 连带前面的若干个数字一起取出来放到组里面。RegExp.$1 就取字符串出来,ru  10.jpg  9.jpg 。通过

padStart()js方法 向前补全字符串,例子中字符串总长度不够补0 ,自行百度此方法。

拓展:
看了这个例子让我觉得用传统的方式超级快完成。当然代码是帅的,

结合下方的网友例子。

ren 命令excel
https://www.kafan.cn/A/x3974odonj.html

用cmd  dir 输出此目录所有文件名,复制到xls中,拼接成:  ren 重命名命令。批量执行。完成。

ren  拔萝卜-10.jpg   baluobo10.jpg

==拓展:

正则表达式引擎

正则表达式是一个很方便的匹配符号,但要实现这么复杂,功能如此强大的匹配语法,就必须要有一套算法来实现,而实现这套算法的东西就叫做正则表达式引擎。简单地说,实现正则表达式引擎的有两种方式:DFA 自动机(Deterministic Final Automata 确定型有穷自动机)和 NFA 自动机(Non deterministic Finite Automaton 不确定型有穷自动机)。

先看这篇记录

java连接3种数据库 JdbcLinkDB 测试 --201801 配置文件放在jar外面 读取,遇到的问题 - 海蓝steven - 博客园
https://www.cnblogs.com/rogge7/p/8269842.html

//-------------------------------

需求:

1、同时测试 mssql,mysql,oracle 三种数据库

2、jar包的形式,配置文件在jar包外面,随时修改

需要找到连接这三个数据库的驱动jar包,添加到项目中

过程:

刚开始不小心打包成jar包 运行jar 提示以下异常:

改成:把项目打包成
Runnable jar,选择主函数入口

运行成功,文件结构如下,考过去使用,Jdk1.8.0_102

一些文件:

start.bat 文件

java -version
java
-jar JdbcLinkDB.jar
pause

jdbcCon.properties文件

# connect oracle
#driver
=oracle.jdbc.driver.OracleDriver
#url
= jdbc:oracle:thin:@localhost:1521:orcl
#username
=system
#password
= 123333# connect mssql
#driver
=com.microsoft.sqlserver.jdbc.SQLServerDriver
#url
= jdbc:sqlserver://127.0.0.1:1433;DatabaseName=GpsDB #username =sa
#password
= 123456# connect mysql
driver
=com.mysql.jdbc.Driver
url
= jdbc:mysql://121.12.249.239:14015/fsjxbdb1 username =fsjxbadmin
password
= fsjxbadmin!23


packagecom.chanbo.yy;importjava.io.FileInputStream;importjava.io.IOException;importjava.io.InputStream;importjava.sql.Connection;importjava.sql.DriverManager;importjava.sql.SQLException;importjava.util.Properties;/***@author**/  
public classConnectionFactory {/*** 数据库连接类*/  
      
    //数据库驱动程序类名
    private static String DRIVER = "";//连接数据库的URL
    private static String URL = "";//连接数据库的用户名
    private static String USERNAME = "";//连接数据库的密码
    private static String PASSWORD = "";privateConnectionFactory(){  
}
static{
getPropertiesInfo();
}
/*** 该方法用来获得属性文件中的driver、url、username、password*/ private static voidgetPropertiesInfo(){
Properties prop
= newProperties();//InputStream inStream = Thread.currentThread().getContextClassLoader()//.getResourceAsStream("jdbcCon.properties");//InputStream inStream = this.getClass().getResourceAsStream("/jdbcCon.properties");//FileInputStream aa ; try{//获得相应的键值对//prop.load(inStream); prop.load(new FileInputStream("jdbcCon.properties"));//prop.load(aa); }catch(IOException e){
e.printStackTrace();
}
//根据相应的键获得对应的值 DRIVER = prop.getProperty("driver");
URL
= prop.getProperty("url");
USERNAME
= prop.getProperty("username");
PASSWORD
= prop.getProperty("password");

}
/*** 该方法用来加载驱动,并获得数据库的连接对象
*
*
@return数据库连接对象conn*/ public staticConnection getConnnection(){
Connection conn
= null;try{//加载数据库驱动程序 Class.forName(DRIVER);
}
catch(ClassNotFoundException e){
e.printStackTrace();
}
try{
System.out.println(
"-- 连接URL : "+URL);//获得数据库连接对象 conn =DriverManager.getConnection(URL, USERNAME, PASSWORD);
System.out.println(
"-- 连接成功");

}
catch(SQLException e){
System.out.println(
"-- 连接失败");
e.printStackTrace();
}
returnconn;
}
}

ConnectionFactory.java


/****/
packagecom.chanbo.yy;importjava.sql.Connection;importjava.util.Scanner;/***@authoryanfazhongxin
*
*/ public classLinkOracleTest {/***@paramargs*/ public static voidmain(String[] args) {//TODO Auto-generated method stub Connection conn =ConnectionFactory.getConnnection();
DbClose.close(conn);
Scanner scan
= newScanner(System.in);
String read
=scan.nextLine();
}

}

LinkOracleTest .java


packagecom.chanbo.yy;importjava.sql.Connection;importjava.sql.PreparedStatement;importjava.sql.ResultSet;importjava.sql.SQLException;importjava.sql.Statement;/***@author**/  
public classDbClose {/*** 数据库关闭类*/  
    /*** 关闭数据库连接 
*
@paramconn 连接类对象*/ public static voidclose(Connection conn){if(null !=conn){try{
conn.close();
}
catch(SQLException e){
e.printStackTrace();
}
}
}
/*** 关闭数据库语句
*
@paramstmt 语句对象*/ public static voidclose(PreparedStatement pre){if(null !=pre){try{
pre.close();
}
catch(SQLException e){
e.printStackTrace();
}
}
}
/***关闭数据库结果集
*
@paramrs 结果集对象*/ public static voidclose(ResultSet rs){if(null !=rs){try{
rs.close();
}
catch(SQLException e){
e.printStackTrace();
}
}
}
public static voidclose(ResultSet rs,PreparedStatement pre,Connection conn){
close(rs);
close(pre,conn);
}
public static voidclose(PreparedStatement pre,Connection conn){
close(pre);
close(conn);
System.out.println(
"数据库已关闭!");
}
}

DbClose.java