class后缀Jmeter接⼝⾃动化-脚本数据分离实例
⼀、背景:
为了让⼤家更加的了解Jmeter,并且使⽤起来游刃有余。
这篇我们主要讲⼀下,如何优雅的使⽤Jmeter⼀步步的实现接⼝⾃动化,完成脚本与数据分离,把可能对Jmeter脚本的维护转移到csv⽂本中,降低接⼝变更时对脚本的维护,最终⽬标是实现写好接⼝⾃动化脚本后,接⼝变更的维护都只要操作csv⽂件。
Jmeter脚本,数据和报告地址:
testerhome地址:
⼆、实例
发那科a柜的process io先介绍⼀个Jmeter的函数-》csvRead函数,后续介绍使⽤的会⽐较多,熟悉的伙伴可以直接跳过。
1、csvRead函数使⽤:
csvRead函数是从外部读取参数,可以从⼀个⽂件中读取多个参数。
api接口操作模式包括
使⽤步骤:
1、先新建⼀个⽂件,例如test.csv(或),⾥⾯的数据存放为
grizz,qq1111
jiezai,qq1111
⽂件为⽤户名和密码,⽤逗号隔开,每⼀列表⽰⼀种参数,每⼀⾏则表⽰⼀组参数。
2、选项-》函数助⼿对话框-》函数助⼿,打开Jmeter的函数助⼿,选择csvRead函数:
其中:
CSV file to get values from | *alias:要读取的⽂件路径,为绝对路径
CSV⽂件列号| next| *alias:从第⼏列开始读取,注意第⼀列是0
即${__CSVRead(D:/test.csv,0)}取到的值为grizz
即${__CSVRead(D:/test.csv,1)}取到的值为qq1111
3.Jmeter执⾏的时候,如果有多个线程,顺序读取每⾏的数据,如果线程组多于⽂件中的⾏数,则循环读取。如线程数为2,则第2个线程读取的是第⼆⾏的数据,线程数为3,线程数3⼤于⽂件中的⾏数2,则第3个线程读取的是第⼀⾏的数据。
PS:这⼀函数并不适合于读取很⼤的⽂件,因为整个⽂件都会被存储到内存之中。对于较⼤的⽂件,请使⽤配置元件CSV Data Set或者StringFromFile 。但是我们不是压测,只是接⼝⾃动化,⼀般没有太⼤的数据⽂件,啊哈哈哈哈。
默认情况下,函数会在遇到的每⼀个逗号处断⾏,需要换⼀个分隔符(通过设置属性csvread.delimiter来实现)
修改jmeter.properties⽂件:
#csvread.delimiter=,
修改为
csvread.delimiter=?
即把分隔符修改为?问号,注意前⾯的#号代表注释,要去掉。重启Jmeter⽣效。
2、使⽤的接⼝:
这⾥我们以两个接⼝举例,其中Content-Type=application/json:
1·获取token的接⼝/getToken
⼊参:
{
"flag":"test",
"appId":"001"
}
返回值:
{"returnFlag":"1000","returnMsg":"获取token成功","token":"19940622"}
2·使⽤token的接⼝/useToken,主要是测试useToken接⼝,useToken接⼝的token需要从getToken接⼝的返回值中取,其实就是参数关联。
⼊参:
{
"flag":"${token}",
"appId":"001"
}
返回值,以3个场景为例:
{"returnFlag":"1000","returnMsg":"使⽤token成功"}
{"returnFlag":"1001","returnMsg":"token为空"}
{"returnFlag":"1002","returnMsg":"token错误"}
对于接⼝的断⾔,我们默认"returnFlag":"1000"即接⼝业务正常返回,1001,1002代表接⼝针对业务的不同异常给予的返回,当然也在我们的接⼝测试范围内。
我们分v1,v2,v3,v4,4个版本循序渐进的讲:
v1版本:
刚开始⼊门时,我们的脚本可能会是这样的
先请求getToken接⼝,并获取token,⽤正则表达式提取如下
再请求useToken接⼝,flag的值输⼊${token},使⽤提取到的token值。
⼊参:{"flag":"${token}","appId":"001"}
返回值:{"returnFlag":"1000","returnMsg":"使⽤token成功"}
断⾔:"returnFlag":"1000",断⾔成功
再测试后续两种场景,⼊参如下:
sampler-使⽤tokenv1-为空:
⼊参:{"flag":"","appId":"002"}
返回值:{"returnFlag":"1001","returnMsg":"token为空"}
python官方文档中文版
断⾔:"returnFlag":"1000",断⾔失败
sampler-使⽤tokenv1-错误:
⼊参:{"flag":"errorToken","appId":"003"}
返回值:{"returnFlag":"1002","returnMsg":"token错误"}
断⾔:"returnFlag":"1000",断⾔失败
查看结果树
这⼀顿操作下来,没啥问题,因为useToken接⼝的3种场景我们都覆盖了,只要把异常的场景的断⾔对应改⼀下,我们的接⼝脚本就写好了,可以交付。但是如果我们要实现接⼝⾃动化,那么v1版本中sampler的重复率⽐较⾼,我们考虑能不能把useToken的3种场景放到⼀个sampler中。
于是有了v2版本
v2版本:
由于聪明的我们有⼀定前瞻性,我们知道,想降低脚本中sampler的重复率,需要借助数据⽂件,我们
可以把接⼝useToken的请求body直接从⽂件中读
⼊参1:{"flag":"${token}","appId":"001"}
⼊参2:{"flag":"","appId":"002"}
⼊参3:{"flag":"errorToken","appId":"003"}
⼊参2,3我们可以从⽂件中读取没问题,但是⼊参1这样从⽂件中读取,”${token}”读取出来的值就是字符串”${token}”,⽽不是我们想要的”19940622”,怎么办呢?
于是我们思考着,可以把接⼝useToken的请求分两种情况,需要正确的token和不需要正确的token,如果需要正确的token,我们就在Jmeter中传给他,其它参数还是可以在⽂本中读取;如果不需要正确的token,则请求全部从⽂件中读取。什么意思呢,继续往下看。
我们设置存放csv⽂件的⽬录DATA=/jmeter/testcase,因为我们可能会多次使⽤到这个⽬录,所以可以⽤${ DATA }代表我们的⽂件⽬录。
useToken_v2.csv⽂件:
⽤例1-token正确?1?"appId":"001"}
⽤例2-token为空?0?{"flag":"","appId":"002"}
⽤例3-token错误?0?{"flag":"errorToken","appId":"003"}
举例:
${__CSVRead(${DATA}/useToken_v2.csv,1)}依次取到的是1,0,0
${__CSVRead(${DATA}/useToken_v2.csv,2)}第⼆次取到的是{"flag":"","appId":"002"}
如果我们useToken_v2.csv⽂件有3⾏,则设置auto_interface_v2线程数为3。
因为对于csvRead函数,每⼀个线程都有独⽴的内部指针指向⽂件数组中的当前⾏。当某个线程第⼀次引⽤⽂件时,函数会为线程在数组中分配下⼀个空闲⾏。如此⼀来,任何⼀个线程访问的⽂件⾏,都与其他线程不同(除⾮线程数⼤于数组包含的⾏数)。
当我们需要正确Token时,我们利⽤if控制器,如果⽂本的第⼆列(我这⾥是以问号分隔的,因为默认是逗号,但是我们接⼝json数据本⾝就有逗号,只能换⼀个)为1,则flag从Jmeter中⾃⼰读取;如果⽂本的第⼆列为0则代表不需要正确token,那接⼝⼊参我们就全部从⽂件中读取。
If:${__CSVRead(${DATA}/useToken_v2.csv,1)}==1
sampler-使⽤tokenv2-haveToken的请求body为:
properties是什么文件{"flag":"${token}",${__CSVRead(${DATA}/useToken_v2.csv,2)}
即请求body由两部分组成,⼀部分来⾃Jmeter内,主要是获取正确的token,另⼀部分来⾃useToken_v2.csv⽂件的第3列。
我们这⾥token正确时,另⼀个参数好像只有"appId":"001"这⼀种情况,显得好像这样写起来更加冗余,其实不然,我们appId也有可能为空,也可能错误。这时候我们的useToken_v2.csv⽂件应该会是这样:
⽤例1-token正确?1?"appId":"001"}
⽤例2-appId为空?1?"appId":""}
⽤例3-appId错误?1?"appId":"error appId "}
⽤例4-token为空?0?{"flag":"","appId":"002"}
⽤例5-token错误?0?{"flag":"errorToken","appId":"003"}
⽽且⼀个接⼝的⼊参不可能只有两个,但⼀般token只会有⼀个,所以当接⼝参数多时,这样写还是减少了⼀定量的sampler的重复率。
If:${__CSVRead(${DATA}/useToken_v2.csv,1)}==0
请求body就为:${__CSVRead(${DATA}/useToken_v2.csv,2)}
再解释⼀下这⾥为什了加了⼀个计算器,和接⼝名称为什么命名为使⽤tokenv2-noToken-${_number}。
⾸先,当我们把线程数设置为3时,其实getToken接⼝也跑了3次,但是其实我们只需要它跑⼀次,取出正确的token就可以了,getToken接⼝的if控制器跟计算器⼀起作⽤,当第1个线程启动时触发if控制器的规则${_number}==1,第2,第3个线程是就不会触发if控制器⾥⾯的getToken接⼝。
useToken接⼝命名后⾯加⼀个${_number},
使⽤tokenv2-noToken-${_number}和使⽤tokenv2-haveToken-${_number};主要是当接⼝报错时,可以根据接⼝的名称(其后⾯加了${_number},接⼝每个场景${_number}都是不⼀样的),判断其对应useToken_v2.csv⽂件的哪⼀⾏导致报错,可快速定位并进⾏报错修改。
⽅便理解,给出运⾏效果图如下:
v3版本:
v2版本我们好像把我们能做的都给做了,但是前提是
从⽂件中读取,”${token}”读取出来的值就是字符串”${token}”,⽽不是我们想要的”19940622”!
随着时间的推移,楼主真的前前后后看过⽹上各种Jmeter教程和使⽤,不下40次,毕竟⾃⼰⼀直有信念,别⼈能做的⾃⼰也可以,1次看不懂的,那就看5次,5次还不懂,10次。不努⼒,没有办法⽐别⼈做得更好的。接着说随着时间的推移,grizz发现那个前提是可以打破的,因为Jmeter有个eval函数。
java虚拟机运行java代码时函数__eval可以⽤来执⾏⼀个字符串表达式,并返回执⾏结果。
举个栗⼦:
name=grizz
SQL=select * from able where name='${name}'
${ SQL }=select * from able where name='${name}'
${__eval(${SQL})}= select * from able where name='grizz'
现在我们可以设置useToken_v3.csv⽂件如下:
⽤例1-token正确?{"flag":"${token}","appId":"001"}?"returnFlag":"1000"
⽤例2-token为空?{"flag":"","appId":"002"}?"returnFlag":"1000"
⽤例3-token错误?{"flag":"errorToken","appId":"003"}?"returnFlag":"1000"
明显的,我们不需要if控制器来判断是否需要正确的Token了,脚本看起来清新了⼀些,⽽且我们把响应断⾔也从⽂件中读取。这样开发修改接⼝的返回提⽰时,我们可以直接通过修改csv⽂件完成对应的修改,不需要去动jmeter脚本。
⼊参:${__eval(${__CSVRead(${DATA}/useToken_v3.csv,1)})}
断⾔${__CSVRead(${DATA}/useToken_v3.csv,2)}
看到这我们可以思考⼀下,在v4版本还有哪些内容可以优化?
v4版本:
v1到v2是⼊门到掌握,v2到v3应该是弱鸡到熟悉,v4应该到星耀了吧,很想写个v5版本,v5(威武),应该很强的怕。
我们想想,我们的最终⽬标是实现写好接⼝⾃动化脚本后,接⼝变更的维护都只要操作csv⽂件。
那么当我们的useToken接⼝新增了⼀个场景,token过期
useToken_v4.csv⽂件
⽤例个数?4
⽤例1-token正确?{"flag":"${token}","appId":"001"}?"returnFlag":"1000"
⽤例2-token为空?{"flag":"","appId":"002"}?"returnFlag":"1000"
⽤例3-token错误?{"flag":"errorToken","appId":"003"}?"returnFlag":"1000"
⽤例4-token过期?{"flag":"oldToken","appId":"003"}?"returnFlag":"1000"
设置线程组auto_interface_v4的线程数为
${__CSVRead(${DATA}/useToken_v4.csv,1)},其实就是⽂件useToken_v4.csv第⼀⾏的第⼆列,就是4
因为我们的线程数与我们的⽂件⾏数挂钩,但这⾥为什么⽂件有5⾏,⽽线程数是4。前⾯说了,因为对于csvRead函数,每⼀个线程都有独⽴的内部指针指向⽂件数组中的当前⾏。当某个线程第⼀次引⽤⽂件时,函数会为线程在数组中分配下⼀个空闲⾏。即Jmeter会分配⼀个线程去保存线程的属性,如线程数,启动时间,循环次数等。即当线程数设置为${__CSVRead(${DATA}/useToken_v4.csv,1)}时,控制线程属性的线程就读取了useToken_v4.csv⽂件的第⼀⾏。
PS:再说⼀下csvRead函数
csvRead函数默认从⽂件第⼀⾏开始读取,除⾮你⼆次开发,不然这个默认就⼀只在(苦笑),就是说我们不好加⽂件列的标题(当然可以利⽤v4版本的第⼀⾏也⾏),降低了⽂件的可读性。但当对某个⽂件进⾏第⼀次读取时,⽂件将被打开并读取到⼀个内部数组中。如果在读取过程中到了空⾏,函数就认为到达⽂件末尾了,即允许拖尾注释。就是我们可以在⽂件写完后回车⼀下,再写⼀些⽂件的注释,或者${__CSVRead(D:/test.csv,next)}了解⼀下,csvRead函数的第⼆个值为next可⾃⾏进⾏⽂件⾏标的切换。
其实当我们的脚本量化后,还有很多东西要考虑的,接⼝csv⽂件的命名规范,线程组和sampler的命
名规范,因为线程组和sampler的名称会在报告中体现,接⼝⼊⼝和出⼝标准,怎么维护我们的数据和脚本更优雅,怎样更⾼效的运⾏脚本和⽣成更丰富的报告,更加的节省测试⼈⼒。
下⼀篇讲⼀下jemter和ant,jenkins的持续集成
接⼝汇总报告:
接⼝详细报告:
欢迎交流指正,感谢阅读。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论