背景

很长一段时间没有测试接口了,接到一个测接口的任务起初竟有点手足无措的感觉,和开发沟通一番需求后很快头脑清晰了,首先考虑的是选取哪个接口测试工具能更方便我测试。

虽然只有两个接口,但这次任务跟以前测接口不同的是这两个接口有关联性,第二个接口的入参需要第一个接口的返回结果,返回结果中还有时间戳。

以前使用的是 postman,还是从 postman 开始吧:1.打开 postman,2.设置测试环境,3.创建接口,4.发送第一个接口成功返回后又手动的去复制返回结果到第二个接口的请求参数,5.改第二个接口的请求测试数据,6.执行接口。

这次测接口的数据 case 比较多,这么对于每一条数据 case 一系列下来感觉左右手一直在执行着粘贴复制点击的操作,因为对 postman 的认识仅限于简单的使用,一些复杂场景的使用还不了解,想着要不试下 jmeter 吧,幸运的是之前有配置过 jmeter,果断使用起来,这么一使用便开始喜欢上这个工具了,有种相见恨晚的感觉,因为比我想象中的功能多很多。

jmeter 的数据传递和处理(参数化):

1.前置处理器和后置处理器:

使用一个框架或者工具,感觉很好使的上手方法就是查看他们的日志,使用 Bean Shell 写完脚本可以先执行一次,看下日志输出是否出错来修改脚本。

2.测试数据:CSV Data Set Config用户定义的变量的节点

刚开始使用了用户定义的变量节点,把接口中使用的所有变量都定义在了这个里面,而且每增加一条数据测试需要改下原有的 httpsampler 或者再添加一条 http Sampler,无形中增大了 jmx 脚本的大小。不知道 jmx 脚本大小对 jmeter 的执行效率有没有影响,但感觉还是文件小一点更好一些,于是选取CSV Data Set Config节点把测试数据放在了一个 csv 文件中。这样数据和 sampler 分离开来了,还有对 excel 使用也很熟悉,这样方便了数据集的修改管理,在使用 csv 这种数据集需要注意线程组中的循环次数,有多少行需要设置循环多少次。

见到其他同学提供的接口参数是 json 格式的,使用逗号分隔的 csv 容易出问题,这样就需要修改读取文件的方式,.txt 或者.dat 都是可采用的格式,在设置上不同而已,具体问题具体分析吧。

3.断言处理器

刚开始使用 jmeter 竟然忽略了 csv 是读取一行的,在 csv 中只设计了接口参数数据而忽略了返回的预期结果,每次执行完后在结果树里一个一个请求的检查返回是不是正确,一天下来眼睛都看花了。后来发现 jmeter 中断言处理器这么好使的一个节点,在设计特殊数据的时候顺便把预期结果设计好,使用断言处理器把 json 结果中的数据提取出来作为实际结果,这样减少了很多手动判断结果的时间,瞬间感觉自由时间多了。

线程组定时器和逻辑处理器

定时器

在测试过程中有个场景需要验证接口发送次数,比如常见的一分钟内能发送接收几次的验证码,或者多长时间内抽了几次奖,定时器还是挺实用的。这次只使用了固定定时器,在线程组中添加固定定时器节点,对于线程组中的每个 http Sampler 都会这么长时间的延时发送。如果通过设置 1 个线程组循环执行多少次,需要计算好执行的时长(调度器设置)。
设置 sampler 延时执行还可以在 sample 之前添加 think time,感觉没有加定时器更准确些,不知道是不是和每个 thinktime 节点的延时时间设置有关系,暂时没有试验。

逻辑处理器

目前用到的不多,上下关联的两个接口可以放在一块儿组成一个事务处理器,如果设置的线程数比较多,发送的数据量比较多这样控制一下结果会清晰很多;如果有些接口在循环执行中只需要执行一次,可以使用 once only controller,比如用在登录,关注,取消关注这样的场景。
逻辑处理器有很多种,可参考这里的说明https://www.cnblogs.com/puresoul/p/4886574.html,以后用到再继续说明。

两个常用的结果监听器

测试结果文件

jmeter 的结果文件一般是.jtl 格式文件,xml 格式的,如果执行的时间比较久,请求参数很多,会生成一个很大的 jtl,根据我们关注点不一样,我们可以对结果的节点进行设置,这样让结果文件小一点。然后可以结合其他语言 python 或者 java 对文件进行简单分析,比如统计各种请求返回码的比例,也可以使用现有的 jtl 文件通过 jmeter 提供的命令转换为 html 报告。

测试执行

执行 jmeter 脚本可以使用 jmeter GUI 执行,使用 GUI 直接打开 GUI 执行脚本就可以;
也可以使用 GUI 设置好各个节点后使用命令执行,jmeter -n -t xxxjmeterscript.jmx -l xxxjmeterlog.jtl,这里-n 表示非 GUI 模式下运行 JMeter,-t 表示要运行的 JMeter 测试脚本文件,-l 记录脚本的文件,常用的是-n,-t,-l,还有-r,启动远程服务,-H,设置 JMeter 使用的代理主机,-P,设置 JMeter 使用的代理主机的端口号,还没有试过。-e,在脚本执行结束后生成 html 报告,-o,用于存放 html 报告的路径;在使用命令生成 html 报告需要注意需要把jmeter.properties文件中的jmeter.save.saveservice.output_format保存格式改为 csv,保存 csv 的时候,有些节点是必须设置的,如果为了减少 csv 文件大小,有些不关心的节点也可以省掉。

#---------------------------------------------------------------------------
# Results file configuration
#---------------------------------------------------------------------------

# This section helps determine how result data will be saved.
# The commented out values are the defaults.

# legitimate values: xml, csv, db.  Only xml and csv are currently supported.
jmeter.save.saveservice.output_format=csv


# true when field should be saved; false otherwise

# assertion_results_failure_message only affects CSV output
#jmeter.save.saveservice.assertion_results_failure_message=true
#
# legitimate values: none, first, all
#jmeter.save.saveservice.assertion_results=none
#
#data type is not required when generate html report,data type column can be removed from csv 
jmeter.save.saveservice.data_type=false
#jmeter.save.saveservice.label=true
jmeter.save.saveservice.response_code=true
# response_data is not currently supported for CSV output
jmeter.save.saveservice.response_data=true
# Save ResponseData for failed samples
#jmeter.save.saveservice.response_data.on_error=false
#jmeter.save.saveservice.response_message=true
#jmeter.save.saveservice.successful=true
#thread_name is required when generate html report,the thread_name column must be in csv column
jmeter.save.saveservice.thread_name=true
#jmeter.save.saveservice.time=true
#jmeter.save.saveservice.subresults=true
#jmeter.save.saveservice.assertions=true
#latency is required when generate html report,the latency column must be in csv column
jmeter.save.saveservice.latency=true
# Only available with HttpClient4
#jmeter.save.saveservice.connect_time=true
jmeter.save.saveservice.samplerData=true
jmeter.save.saveservice.responseHeaders=true
jmeter.save.saveservice.requestHeaders=true
#jmeter.save.saveservice.encoding=false
#bytes is required when generate html report,the bytes column must be in csv column
jmeter.save.saveservice.bytes=true
# Only available with HttpClient4
# sent_bytes is not required when generate html report,sent_bytes column can be removed from csv 
jmeter.save.saveservice.sent_bytes=false
#url is not required when generate html report,url column can be removed from csv 
jmeter.save.saveservice.url=false
#jmeter.save.saveservice.filename=false
#jmeter.save.saveservice.hostname=false
#jmeter.save.saveservice.thread_counts=true
jmeter.save.saveservice.sample_count=true
#jmeter.save.saveservice.idle_time=true

使用非 GUI 时,可以重新设置概要采集的时间间隔,默认的是 30s

#
# interval between summaries (in seconds) default 30 seconds
summariser.interval=30

有个问题是设置了执行时长同一个脚本,使用命令执行时发送的请求数比用 GUI 的多一些,或许使用非 GUI 模式省下的资源有用在这里了。还有 jmeter 线程数设置可能也跟电脑性能有关系,设置到 300 以上总是报错,以下倒是可以。

压测过程

jmeter 的压测过程中,数据的变化看起来不太直观,而且也不实时,jmeter 提供了 Backend Listener 监听器,可以和 influxDB 和 Grafana 这两个结合起来使用,这样 jmeter 把显示实时数据的任务交给其他工具展示。这三者的配置和使用方法可以参照 https://www.jianshu.com/p/5901d7b82205 。在配置过程中要注意 2003 是 jmeter 和 influxdb 通信的端口,还有个好像是 8086,是 influxdb 和 grafana 通信的默认端口。

环境调通,接下来是在 Grafana 中设置图表要显示的项目,好不好看就全靠自己了,这也是一个慢慢熟练的过程,挺有趣的。Grafana 可选择显示的字段和 jmeter 的实时结果中各字段是对应的,可以从http://jmeter.apache.org/usermanual/realtime-results.html 查找到后再去 Grafana 中设置。

### 问题

每次执行 jmeter 命令都要手动修改命令的各个参数后才开始执行,于是把参数生成和命令执行写在批处理文件中了,和直接在 cmd 窗口中输入命令执行不一样的地方是输出的内容不会写在指定的文件中了,暂时还不知道什么原因,用到的整个脚本是:

rem *** need to set java and jmeter system variables in advance.And need an executable jmx script,my script name is "zhengshihuanjingdata_v2" ***
rem get time and date for createing filename,
set CURRENTDATE=%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%
echo  %CURRENTDATE%

set CURRENTTIME=%TIME:~0,2%%TIME:~3,2%%TIME:~6,2%%TIME:~9,2%
echo  %CURRENTTIME%


set CURRENTTS=%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%%TIME:~0,2%%TIME:~3,2%%TIME:~6,2%%TIME:~9,2%

set "CURRENTTS=%CURRENTTS: =%"
echo CURRENTTS

set JMXFILENAME=zhengshihuanjingdata_v2


rem create jtlreport,summaryreport,htmlreport directory in current dir if doesn't exist these.

set JTLFOLDER=jtlreport\
set SUMMARYFOLDER=summaryreport\
set HTMLFOLDER=htmlreport\

if exist %~dp0%JTLFOLDER% (
    rem jtlreport directoy exists
    echo jtlreport directoy exists
) else (
    rem jtlreport directoy doesn't exist,need to create
    echo %JTLFOLDER% directoy doesn't exist, create %JTLFOLDER%
    md %~dp0%JTLFOLDER%
)

if exist %~dp0%SUMMARYFOLDER% (
    rem summaryreport directoy exists
    echo %SUMMARYFOLDER% directoy exists
) else (
    rem summaryreport directoy doesn't exist,need to create
    echo %SUMMARYFOLDER% directoy doesn't exist, create %SUMMARYFOLDER%
    md %~dp0%SUMMARYFOLDER%
)

if exist %~dp0%HTMLFOLDER% (
    rem htmlreport directoy exists
    echo %HTMLFOLDER% directoy exists
) else (
    rem htmlreport directoy doesn't exist,need to create
    echo %HTMLFOLDER% directoy doesn't exist, create %HTMLFOLDER%
    md %~dp0%HTMLFOLDER%
)

pause
rem call bat2.bat %~dp0%JMXFILENAME% %~dp0%JTLFOLDER%%CURRENTTS% %~dp0%HTMLFOLDER%%CURRENTTS% %~dp0%SUMMARYFOLDER%%CURRENTTS%
jmeter -n -t %~dp0%JMXFILENAME% -l %~dp0%JTLFOLDER%%CURRENTTS%.jtl -e -o %~dp0%HTMLFOLDER%%CURRENTTS% ^>^> %~dp0%SUMMARYFOLDER%%CURRENTTS%.txt
pause

为了看下 summary 的数据,后来还是改用 python 实现将 cmd 的输出写入到文件中。

post 请求参数中有中文

post 请求是 json 格式的数据并且含有中文,在使用 jmeter3.3 的时候发送到服务器出现了乱码,虽然已经将 cotent encoding 设置成 utf-8,还是需要先将中文转换为 Unicode 才行,不知道是我设置的问题还是 3 本身的问题,一样的设置在 jmeter5 上倒是很顺利。。

jmeter 对非 http 接口的支持

目前接触到最多的就是 http 接口了,其他类型的接口用到再探索吧。


↙↙↙阅读原文可查看相关链接,并与作者交流