简述一下背景,被测系统为阅卷系统,主流程大概是:创建考试->扫描识别学生答题卡上传至系统->预处理->分配批阅->批阅->生成报告。
本次主要压测多老师进入批阅试卷的场景;登录与批阅为两个线程组。
涉及登录相关脚本在之前文章中已有写过Jmeter实现RSA加密进行单点登录,本篇文章在此基础上进行优化调整。
1、自定义变量参数化
通过“用户自定义变量”的设置,将部分“关键”参数,如IP地址、端口号、用户名,密码,批阅考试编号等信息,集中且单独拎出来,这样可加强脚本的可移植性,可在测试环境、开发环境、线上环境下,简单修改下“用户定义的变量”值即能运行起来的目的,其他非关键参数可由脚本根据逻辑进行自动赋值。
测试计划下面,添加--用户自定义变量,可配置部分“关键”参数,运行前自由进行参数值的设置,如下:
以上参数字段在各请求处用到时,需用${参数名称}替代,如:${UserAccessIP}
2、正则提取登录Cookie信息
登录后,再进入业务系统请求时,从Fiddler抓取的信息中可以看到,请求头中带有Cookie信息,其下有3个变量参数:
在稍作研究下,可以发现以上参数中,/mark-paper请求返回了JSESSIONID信息,而/mark-paper/frame/index.do请求返回了XSRF-TOKEN和SESSION信息。
【以上可能会有疑问,/mark-paper和/mark-paper/frame/index.do有啥区别,实际都是指同一个系统,这是我们项目特有的一个原因,在我之前文章中也有解释过,由于项目有多个子系统的,需要先访问子系统的url,会自动跳转到/login,此时登录成功后,才会再次成功进入子系统的url。】
现在我们只要在对应请求下面提取cookie信息即可;在对应请求下添加--后置处理器--正则表达式提取器,进行各参数提取。
3、补充:正则表达式提取器的使用说明
在做Jmeter接口或性能测试时,避免不了需要提取上一接口返回的值,作为下一接口请求时须传递的参数,就是常说的关联。
通常使用正则表达式提取器来实现,本小节对正则表达式提取器页面的各字段使用做简要说明:
名称:任意填写
注释:任意填写
Apple to:作用范围,主要有以下选项,通常默认即可
1、Main sample and sub-samples:作用于主节点及对应子节点的取样器
2、Main sample only:仅作用于主节点的取样器,该项为默认取值
3、Sub-samples only:仅作用于子节点的取样器
4、JMeter Variable:作用于jmeter变量,其后输入框内输入jmeter的变量名称,从指定变量值中提取需要的值。
要检查的响应字段:要提取的参数所在位置范围,选项很全面,根据情况选择
1、主体:响应报文的主体,常用选项
2、Body(unescaped):主体,替换所有html转义符的响应主体内容,html转义符处理时不考虑上下文,可能有不正确的转换,不建议使用
3、Body as a Document:从不同类型的文件中提取文本,该选项比较影响性能
4、信息头:响应信息头,常用选项
5、Request Headers:请求信息头
6、URL:请求URL
7、响应代码:响应状态码,如200、404等
8、响应信息:响应信息
引用名称:自己定义的变量名称,后续请求将要引用到的变量名,如填写的是:stuExamUuid,后面的引用方式是${stuExamUuid}
正则表达式:提取内容的正则表达式,相当于LoadRunner中的关联函数;“( )”括号括起来的部分就是需要提取的内容,前后是提取的边界内容。使用方法可参考官方说明,以下为常用操作符:
. 匹配任何字符
+ 匹配一次或多次(懒惰),至少是1次
* 匹配零次或多次(贪婪),可以是0次
? 匹配零次或一次(占有), 停止在第一个匹配成功时
?=XXX 匹配XXX前面的位置
?<=XXX 匹配XXX后面的位置
模板:用$$引用起来,若在正则表达式中有多个正则表达式(多个括号括起来的),则可以用$1$,$2$,$3$等,表示把提取到的第几个值赋给变量。
$-1$:表示取所有值
$0$:表示随机取值
$1$:表示取第1个
$2$:表示取第2个
以此类推:$n$:表示取第n个
匹配数字:正则表达式匹配数据的结果可以看做一个数组,0代表随机取值,-1代表所有值,正数n则表示取第n个值(比如1代表取第1个值)
缺省值:正则表达式没有匹配到值时,使用此缺省值
最后,想验证正则表达式提取的内容是否正确,可以在请求后加入调试取样器
4、Cookie参数全局变量(属性)处理
变量是每个线程独有的,属性是Jmeter的全局属性,属性可用于在线程和线程组之间进行通信,故通过设置参数的属性可以实现跨线程传参。通过BeanShell 后置处理器和__setProperty函数可实现。
在对应参数的请求下,添加--后置处理器--BeanShell 后置处理程序,进行如下配置:
__setProperty设置属性函数说明
语法格式:${__setProperty(name,value,true)}
参数讲解:
字段 | 含义 | 是否必传 |
Name | 属性名 | YES |
Value | 属性值 | YES |
True/False | 是否返回原始值? | NO |
通过函数助手,可以快速生成表达式:
说明:经过函数setProperty处理后,后面在使用时,需要读取其属性名,如${__setProperty(TH_XSRF-TOKEN,${XSRF-TOKEN},)}; 后续使用时,需要读取TH_XSRF-TOKEN名称来获取值。
经过以上处理,JSESSIONID,XSRF-TOKEN和SESSION已经具有全局变量属性。
5、跨线程组调用Cookie信息
Jmeter在跨线程组调用具有全局属性的参数时,通过__P函数来读取对应的属性值。如下图,阅卷管理线程组调用登录线程组中的Cookie信息(JSESSIONID,XSRF-TOKEN和SESSION值)时,只要在阅卷管理线程组下的HTTP Header Manager中添加Cookie及其值就可:
名称:Cookie
值:
JSESSIONID=${__P(TH_JSESSIONID,)};XSRF-TOKEN=${__P(TH_XSRF-TOKEN,)};SESSION=${__P(TH_SESSION,)}
__P读取属性函数说明
语法格式:${__P(name,default)}
参数讲解:
字段 | 含义 | 是否必传 |
Name | 需要读取的属性名 | YES |
DefaultName | 属性默认值值 | NO |
通过函数助手,同样可以快速生成表达式。
6、多用户登录实现
仍然用在跨线程组的情况下,在以上基础上进行调整:
1、用户自定义变量中输入用户名/密码的方式不太适合多用户的情况,需改用通过调用存有用户名/密码信息的数据文件来传递登录参数。
2、将用户的Cookie参数设置属性,不能解决多用户的不同Cookie信息传递;可以改用将不同用户的Cookie信息保存到数据文件中。
3、其他线程组可调用Cookie数据文件中信息来实现多用户登录。
登录信息通过数据文件调用
准备带有多个登录用户名、密码的数据文件,如txt、csv文件等
在登录线程组下面,添加--配置元件--CSV 数据文件设置,进行如下图配置:
其他和之前一样,即登录请求相关参数用到用户名、密码的字段,均用${username}、${password}表示。
Cookie信息保存到数据文件
在登录线程组--登录进入业务系统的请求下面,添加--后置处理器--BeanShell 后置处理程序,进行如下Script的编写。
脚本摘要:
//指定Jmeter目录(与bin同目录)下mark_paper_data文件夹路径
String path = "..//mark_paper_data";
//判断路径下文件夹是否存在,不存在则创建文件夹
File file = new File(path) ;
if(!file.exists()) {
file.mkdirs();
}
//创建文件并追加写入数据方式
FileWriter fstream = new FileWriter("..//mark_paper_data//session.txt",true);
BufferedWriter out = new BufferedWriter(fstream);
//写入JSESSIONID、XSRF-TOKEN、SESSION信息到session.txt中
out.write(vars.get("JSESSIONID") +"," + vars.get("XSRF-TOKEN") +"," + vars.get("SESSION"));
//换行操作,每写入一个用户Cookie信息后进行换行,一行代表一个用户,方便后面调用读取
out.write(System.getProperty("line.separator"));
out.close();
fstream.close();
配置12个用户,登录线程数设置12,运行后得到session.txt中有12行数据,分别记录12个用户的Cookie信息,如下图
因用户的Cookie信息是追加写入session.txt中的,每次脚本执行完,session.txt文件中都会存有本次执行留下的Cookie信息,为清理历史数据,在每次执行前,做删除session.txt的操作。在测试计划下面,添加--前置处理器--BeanShell 预处理程序,进行如下Script的编写。
脚本摘要:
String path1="..//mark_paper_data//session.txt"; //指定session.txt文件路径
File file1=new File(path1);
file1.delete(); //删除session.txt文件
调用Cookie数据文件来实现多用户登录
在阅卷管理线程组下面,添加--配置元件--CSV 数据文件设置,进行如下图配置:
在阅卷管理线程组下的HTTP Header Manager中修改Cookie如下:
名称:Cookie
值:JSESSIONID=${JSESSIONID};XSRF-TOKEN=${XSRF-TOKEN};SESSION=${SESSION}
通过以上的方式,可以实现多用户登录,以及登录信息跨线程组间进行其他业务的并发测试。
7、断言
在关键业务请求后,建议添加断言,已验证该请求执行是符合预期的。Jmeter提供的断言方式比较多,目前常用的是响应断言,页面下图样子。
执行“批阅--提交打分”的请求,正常执行成功后,会在Response Body中返回:
{"success":true,"displayMsg":"操作成功","detail":null,"logMsg":null}
所以断言时,在响应文本中匹配到字符串“操作成功”即断言该请求成功。
执行“进入待批阅”请求时,正常执行成功后 ,Response Body中会显示该页面特有的元素信息,可以用这些特有的元素作为匹配的字符串进行执行成功的断言。
若不加断言,请求的执行结果其实并不是预期结果时,但也会标记执行成功,就干扰了我们的测试。
8、线程组执行顺序问题
一个脚本文件中,如有多个线程组,并且想让他们从上到下依次执行,只需在测试计划页面,勾选“独立运行每个线程组”即可。
以上若不勾选,不同线程组间,会同步执行。