基于Java语言的压力测试工具,可以做接口测试,也可以做性能测试
需要安装JDK1.8以上,需要配置环境变量
File Structure | Description |
---|---|
backups | 脚本备份目录,格式JMX |
bin | 存放Jmeter启动脚本,配置文件,模块文件等 |
docs | 离线帮助文件 |
extras | 存放与第三方的集成构建文件,集成Ant或者Jenkins |
lib | 存放库文件,jar包 |
license | 许可证文件 |
组件类型 | 描述 |
---|---|
测试计划 | 所有组件的容器 |
线程组 | 模拟一定数量的用户 |
取样器 | 向服务器发送请求的最小单元 |
逻辑控制器 |
结合取样器实现一些复杂的逻辑 |
前置处理器 |
在取样器之前的工作 |
后置处理器 |
在取样器之后的工作 |
断言 |
用于判断请求是否成功 |
定时器 |
负责在请求之间的延迟间隔;固定,高斯,随机 |
配置元件 |
配置信息 |
监听器 |
负责收集结果 |
执行顺序:测试计划->线程组->配置原件->前置处理器->定时器->取样器->后置处理器->断言->监听器
作用域:
必要组件: 测试计划、线程组、取样器
辅助组件:必要组件之外的,作用于父组件,同级组件,以及同级组件下的所有子组件
线程组元件是任何一个测试计划的开始点。在一个测试计划中的所有元件都必须在某个线程下。所有的任务都是基于线程组
4.1.1 setup thread group
一种特殊类型的ThreadGroup,用于在执行常规线程组之前执行一些必要的操作。在"setup thread group"下提到的线程行为与普通线程组完全相同。不同的是执行顺序---它会在普通线程组执行之前被触发。
应用场景举例:
A、测试数据库操作功能时,用于执行打开数据库连接的操作。
B、测试用户购物功能时,用于执行用户的注册、登录等操作。
一种特殊类型的Thread Group,用于在执行常规线程组完成后执行一些必要的操作。在"teardown thread group"下提到的线程行为与普通线程组完全相同。不同的是执行顺序---它会在普通线程组执行之后被触发。
应用场景举例:
A、测试数据库操作功能时,用于执行关闭数据库连接的操作。
B、测试用户购物功能时,用于执行用户的退出等操作
tips:
默认情况下,如果在测试计划中勾选了"Run tearDown Thread Groups after shutdown of main threads",则主线程运行结束会运行它,如果不勾选且测试按预期完成,则tearDown线程组将不会运行
这个就是我们通常使用的线程。通俗的讲,一个线程组可以看做一个虚拟用户组,线程组中的每个线程都可以理解为一个虚拟用户。多个用户同时去执行相同的一批次任务。每个线程之间都是隔离的,互不影响的。一个线程的执行过程中,操作的变量,不会影响其他线程的变量值
线程属性
A. 线程数: 线程数也就是并发数,每个线程将会完全独立的运行测试计划,互不干扰。多个线程用于模仿对服务器的并发访问
B. Ramp-Up时间(秒): 设置启动所有线程所需要的时间
C. 循环次数: 每个线程循环的次数,如果次数设置为1,那么JMeter在停止前只执行测试计划一次
D. 延迟创建线程直到需要: 默认情况下,测试开始的时候,所有线程就被创建完了。如果勾选了此选项,那么线程只会在合适的需要用到的时候创建
线程调度器:
A. 持续时间(秒): 控制测试执行的持续时间,以秒为单位
B. 启动延迟(秒): 控制测试在多久后启动执行,以秒为单位
例如有以下需求,模拟发送10000的包,循环1次,在10分钟内1000个用户全部发送完,则相当于1分钟100用户在发送完请求
作用: 用于提供对静态数据配置的支持. CSV Data Set config可以将本地数据文件形成数据池(Data Pool), 而对应于HTTP Request Sampler和TCP Request Sampler等类型的配置元件则可以修改Sampler的默认数据
作用: 支持用户通过csv文件传递参数给取样器配置CSV文件,使用notepad++转码为utf-8
线程组添加csv数据文件设置: 线程组--->配置元件--->csv数据文件设置
参数说明:
参数类型 | 描述 |
---|---|
文件名 | 直接选择准备好的csv文件 |
文件编码 | UTF-8 |
变量名称 | 自定义,单个直接写变量名即可,如果有多个用英文逗号隔开 |
忽略首行 | 如果csv文件首行写的是变量名称则选择忽略首行True,如果直接是数据则选择False |
分隔符 |
如果csv文件使用的是逗号隔开,就保持默认值 |
- | 剩余选项保持默认值即可 |
同级子取样器使用时,通过${变量名}来使用即可,如果要使用所有csv文件数据,则设置线程组当中的线程数或者循环数和数据数量一致即可
支持用户添加或者重写HTTP请求头。JMeter支持多个信息头管理器。多个信息头条目合并成一个信息头列表,跟随http请求一并提交到服务端
当有多个信息头管理器,且不同的管理器内有名称相同的信息头条目存在时,顺序靠前的管理器的信息头条目会覆盖后面的;
当只有一个信息头管理器,但管理器内有名称相同的信息头条目时,会同时生效;
常用的请求头如下:
储存在用户本地终端上的数据,主要用于默认cookie管理
通常情况下,当用户结束浏览器会话时,系统将终止所有的cookie,当web服务器创建了Cookie后,只要在其有效期内,当用户访问同一个Web服务器时,浏览器首先要检查本地的cookies,并将其原样发送给web服务器
作用:
发送请求,经常要校验cookies信息
录制时使用的cookie管理器,只能在指定的域下面使用,如果服务器地址切换,发现发送请求时,就会出现no cookies
最典型的应用:
A. 判断注册用户是否已经登录网站,用户可能会收到提示,是否在下一次进入此网站时保留用户信息以便简化登录手续
B. 购物车之类的处理,用户可能会在一段时间内在同一家网站的不同页面中选择不同的商品,这些信息都会写入cookies,以便在最后付款时提取信息
如果,禁用了HTTP Cookie管理器的话,登录成功,但访问其它页面时都跳转到了登录页面
基本设置:
可以设定一些缺省值,假设有10个请求,访问域名和端口都是一样的,那HTTP请求中就不再需要单独配置了,比较方便(增加脚本的移植性)
高级设置:
待更新
测试计划中添加数据库驱动jar包,切记jar包的版本需要与数据库版本一致, 也可以将目标的jar包拷贝到jmeter\lib目录下
1. 下载地址: MySQL :: MySQL Downloads
2. 选择MySQL Community(GPL)Downloads -->Connector/J-->Archives-->目标版本+Platform Independent
3. 在线程组中添加JDBC Connection Configuration
A. 在variable Name for created pool中填写要连接的数据库名称---
B. 在Database Connection Configuration填写数据库相关参数
C. 数据库连接地址:
D. jdbc:mysql://数据库域名或者ip:端口/数据库名称
E. 选择数据库驱动: com.mysql.jdbc.Driver
F. 数据库用户名
G. 数据库密码
4. 配置JDBC Connection Configuration
A. Variable Name Bound to Pool中填写和写数据库时一致的名称
B. 写sql语句
tips: 如果查询的数据提示日期格式不规范,可在Database URL后添加以下字段: ?ZeroDateTimeBehavior=CONVERT_TO_NULL
作用:用于在实际请求发出之前对即将发出的请求进行特殊处理
哪个取样器需要使用参数就在这个取样器下添加,可以添加变量或者用户,按照实际的数据传给取样器使用,如果有多组数据,可以通过修改线程组的线程数来达到效果,切记不要修改循环次数,否则只会使用第一组数据
例如:
用户数据如下,两个参数username和password,一共有两组数据
取样器这里用HTTP请求,发送一段json字段,使用用户数据
tips: 在测试计划页面也可以直接添加用户定义的变量,这样该测试计划下的所有元件都可以使用,用法和上面一样 ${变量名}
用于操作之间设置等待时间,等待时间是性能测试中常用的控制客户端QPS的手段, jmeter定义了固定定时器、常数吞吐量定时器、高斯随机定时器等不同类型的时间
以固定的时间间隔执行
作用: 该集合点一般使用在具体接口下,哪个接口需要使用集合点则添加
参数说明:
模拟用户组的数量: 即每次集合的用户数
超时时间以毫秒为单位:
A. 时间设置为0表示无限等待,直到线程数=集合数量(在线程组中设置的线程数)
B. 设置具体时长则表示在规定时间内启动已集合的线程,不管是否达到预期集合的数量
tips: 1. 集合数最好可以被线程组中的线程数整除。2.集合数启动时间(超时时间)最好大于线程组启动的时间(Ramp-Up)
作用: 向服务器发送请求且记录响应时间和响应内容
作用: 用来向服务器发送HTTP/HTTPS请求
参数说明:
参数 | 子参数 | 描述 |
---|---|---|
Name | - | 组件名,可以修改 |
Comment |
- | 注释信息,可写可不写 |
Web Server |
Protocol[http] | 不写就是默认的HTTP,可以根据实际情况指定 |
Server Name or IP |
IP或者域名,比如cn.bing.com(不要加http://,默认就带;不能有路径) |
|
Port Number |
具体的端口号,HTTP默认为80,HTTPS为443 | |
HTTP Request | Method | GET, POST, HEAD, TRACE, OPTIONS, PUT, DELETE, PATCH (不支持JAVA实现) |
Path | 发送的路径,/表示根目录 | |
Content encoding |
内容编码,如果请求有乱码的话可以将其配置为UTF-8或者ANSI |
|
配置项 |
默认值即可。自动重定向,关注重定向,使用KeepAlive等 |
|
Parameters |
- | 配置请求参数,比如添加name:q,value:gloryroad |
Body data |
- | json请求的请求体。Parameters中有数据时不能点击Body Data,需要先将Parameters中的数据删除 |
Files upload |
- | 上传文件,一般不用,上传方式有两种;第一种方式,在mime写入: multipart / form-data, 第二种是勾选“对POST使用multipart / form-data”, 然后高级-->客户端实现-->Java; 文件名称是具体要上传的路径,路径用\\, 例如: E:\\1.txt,参数名称输入要上传的参数变量名 |
tips: Parameters和Body data不能共存
注: 如果发送的HTTP请求返回有乱码(中文字符等), 在发送请求的时候带上编码格式encoding:UTF-8, 如果添加了还是没用,需要修改Jmeter本身的全局变量属性,路径: 安装目录\bin\jmeter.properties添加: sampleresult.default.encoding=UTF-8
作用: 通过SQL语句发送请求到数据库返回相应结果,需要配合JDBC Connection Configuration使用
参数说明:
参数 | 描述 |
---|---|
测试计划 | 添加用户变量 user 具体值 |
SQL语句 |
SELECT Host FROM mysql.user where user='${user}', 引号和美元符不能省略 |
Variable Name Bound to Pool |
填写JDBC Connection当中一致的数据库名称即可 |
Query Type |
Select Statement(查询),Update Statement(更新)等等... |
Parameter values |
数据的参数值,此处为空即可 |
Parameter types |
char数据的参数类型。可去数据库中选择要查询的表-->设计表-->查看当前user的类型,示例中为char |
Variable names |
user,就是保存SQL语句返回结果的变量名 |
Result variable name |
创建一个对象变量,保存所有的返回结果 |
Query timeout |
查询超时时间 |
Handle result set |
定义如何处理由callable statements语句返回的结果 |
作用: 用于对sampler发出请求后得到的服务器响应进行处理,一般用来提取响应中的特定数据
作用: 在接口返回值为HTML或xml格式时,使用xpath提取器
参数说明:
A. 引用名称: 接收返回值数据的变量名
B. XPath query: xpath的表达式,一般是标签名
C. 匹配数字: 0表示随机选择,-1表示取所有,其他数字是几就表示取第几个
D. 缺省值: 当没有找到对应数据的时候显示缺省值的内容
E. XML Parsing Options: 选择Use Tidy和Quiet选项
示例
访问网页页面获取title然后将title当中变量传入百度进行搜索
title作为变量在下方访问百度的http请求中路径输入 s?wd=${title}
作用: 在接口返回值为json类型时,使用json提取器
参数说明:
A. Names of created variables: 接收返回值数据的变量名 例如session
B. Json path expressions: json_path的表达式,$.获取字段名 例如$.session, $[“session”],复杂节点类似于 $.session[11].name,包含下标和子节点
C. Match No.(0 for Random): 0表示随机选择,-1表示取所有,其他数字是几就表示取第几个Default Values: 当没有找到对应数据的时候显示缺省值的内容
作用: 运行用户使用正则表达式提取数据,适用任何返回形式
参数说明:
A. 引用名称: 接收返回值数据的变量名 例如: access_token
B. 正则表达式:使用正则表达式解析响应的结果 “()”表示提取字符串中的部分值
C. 模板:$1$ 表示取第一组数据,启用多个就是$1$$2$类似拼接
D. 匹配数字:1表示取第一个
E. 缺省值:Not found
常用正则表达式说明:
. 代表匹配任意一个字符
[0-9]代表匹配0-9之间任意一个数字
[a-z]代表匹配a-z之间任意一个字母
[A-Z]代表匹配A-Z之间任意一个字母
+ 匹配一次或多次
?代表匹配一次或一次也没有,当放置到*号后,标识的数据是非贪婪的
* 匹配0次或多次
\d匹配数字[0-9]
\w匹配[a-z A-Z 0-9]
\b[a-z]{3}\b: \b代表边界
示例:
当前图片是正则表达式和Jsonpath提取器对登录某些网站需要保存access_token内容进行提取,以供接下来的其他取样器使用示例
作用: 判断实际结果和预期结果是否一致
断言状态码+断言内容
配置断言:
A. 测试字段中选择响应代码
B. 测试模式中添加期望的状态码
示例:
如果断言成功和正常一致,异常则是因为断言当前状态嘛和设置不一致
作用范围: 返回值格式为JSON的断言
配置JSON断言:
A. Assert JSON Path exists: 获取返回结果的字段---实际结果
B. Expected Value:预期结果,可以输入具体数据也可以传入参数
作用范围: 断言返回值所占的字节数
配置大小断言:
Size to Assert: 具体字节大小 通过实际所占字节数和设置的字节数比较来断言
举例:
字节大小: 20 比较类型 > 则表示实际结果所占字节大于20为PASS
作用范围: 当前接口请求执行的时间
配置持续时间断言
持续时间(毫秒):具体响应时间
举例:
持续时间: 50毫秒 则只要执行时间大于设置的持续时间则FAIL
监听器主要常用的就是查看结果树,当执行并发测试的时候,可以通过添加汇总报告,聚合报告等收集数据。
Jmeter逻辑控制器可以控制采样器(sampler)的执行顺序,它由多个逻辑控制语句封装成不同功能的组件组成,只对其子节点的sampler有效
Jmeter提供了多种逻辑控制器,大致分为2种类型:
A. 一类是用于控制测试计划中sampler节点发送请求的逻辑顺序的控制器,常用的有[如果(if)控制器]、[switchController]、[Runtime Controller]、[循环控制器]等。
B. 另一类是对测试计划中的脚本进行分组 ,方便Jmeter统计执行结果,常用的有[Throughput Controller(吞吐量控制器)]、[Transaction Controller(事务控制器)]等。
作用:条件成真,则执行控制器下所有取样器
使用方法及步骤:
A. 测试计划-->线程组-->用户自定义变量
B. 线程组-->逻辑控制器-->如果(If)控制器
C.如果(If)控制器-->HTTP请求
D. 测试计划-->查看结果树
参数说明:
A. Expression(must evaluate to true or false):表达式(值必须是true或false),也就是说,在右边文本框中输入的条件值必须是true或false, (默认情况下)
B. Interpret Condition as Variable Expression?:默认勾选项,将条件解释为变量表达式(需要使用__jexl3 or __groovy 表达式)
C. Evaluate for all children?:条件作用于每个子项(具体理解见后面的列子说明)
D. Use status of last sample: ${JMeterThread.last_sample_ok}可用于检测最后一个取样器是否成功执行
tips:
1. 文本框上的黄色感叹号,就是提示你,建议采用__jexl3 or __groovy 表达式,以提高性能,也就是默认的方式。
2. if 控制器 只能作用于其下的子项
如果不知道表达式如何使用,可以通过函数表达式来生成,示例如下:
如果使用groovy则表达式为: ${__groovy(1==1,)}
拷贝字符串:${__jexl3(1==1,)}到Expression...那一栏即可,如果发现字符串无法复制,是因为你的Jmeter是5.3,5.4,5.4.1版本,可以参照以下链接重新提取一份ApacheJMeter_core.jar包到Jmeter\lib\ext目录,然后重启Jmeter即可
如果是用户变量的情况,例如名称:time value:9
控制器参数设置如下: ${__jexl3("${time}"==9,)}
作用: ForEach控制器一般和用户定义的变量一起使用,在用户自定义变量中读取一系列相关的变量
使用方法及步骤:
A. 测试计划-->线程组-->用户自定义变量
B. 线程组-->逻辑控制器-->ForEach控制器
C. 如果(If)控制器-->HTTP请求
D. 测试计划-->查看结果树
参数说明:
A. 用户定义变量名称书写(前缀+数字): 例name_1、name_2....
B. 输入变量前缀: 输入要遍历变量的前缀
C. 开始循环字段(不包含): 遍历变量开始的索引(从0开始)
D. 结束循环字段(含):遍历变量结束的索引(不包含索引)
E. 输出变量名称: 定义要被引用的变量名称
F. 数字之前加上下划线“_”?(默认勾选)
用户变量设置,示例如下:
ForEach控制器设置如下: 变量名为name,开始从0即为第一个开始,结束循环第5个索引,输出变量为search
tips:切记变量名最好连续,如果是name[6-10],则索引设置开始5,结束10
以下用百度举例,通过上面取出的search值进行查询
查询结果会显示5个
作用: 循环执行控制器下的所有取样器
当前取样器循环执行5次,示例如下
tips: 该循环控制器只能控制它控制的取样器,如果线程组也有循环,则循环次数相乘,如果有多个控制器,它不影响其他控制器下的取样器
总结参数化:
A. CSV数据文件配置: 适应大量测试数据时使用,位置在配置元件中
B. 用户参数:适用于少量测试数据,位置在前置处理器中
C. 用户定义的变量: 适用于常量配置(数据库地址,测试环境地址,登陆数据等),位置在测试计划和配置元件中,了解作用域的概率就知道使用范围了
添加步骤:通过点击jmeter的函数助手,选择需要使用的函数,设置函数相关参数,点击生成,复制函数字符串,粘贴到需要使用的位置
举例:
设置访问百度页面有10个线程组,设置counter函数到名称查看统计结果
常用的还有随机函数,时间函数等
作用: 实现多个线程组之间的数据传递
配置说明:
1. 将原来的参数提升作用域,使用函数:setProperty
2. 设置setProperty
1). 属性名称:指提升作用域后的变量名称
2). Value of property: 需要提升作用域的变量值 ${变量名}, 变量名是后置处理器当中例如json提取器设置的变量
3. 在线程组1中(关联线程组至少为2个及以上)添加一个新的取样器--Bean Shell取样器
4. 将设置好的setProperty函数复制粘贴到Bean Shell取样器中
5. 设置Property函数
1). 属性名称:提升作用域后的变量名称
6. 将设置好的Property函数复制粘贴到线程组2及以后线程
7. 设置线程组请求的先后顺序
1). 线程组勾选调度器
2). 填写持续时间和启动延迟
分布式概念: 有多台执行机共同完成一个任务的部署,这种部署就是分布式
执行机:
A. 获取本机的IP地址,然后修改jmeter.properties当中的remote_hosts=ip:1099,1099是jmeter分布式的默认端口,也可以自定义
B. 执行机需要关闭防火墙
C. 执行机有多个网卡或者虚拟端口时需要都关闭
D. 执行机运行jmeter-server.bat
控制机:
A. 将执行机的ip写入jmeter.properties的remote_hosts,端口保持一致,如果有多个执行机,则用逗号隔开
B. 如果控制机需要执行脚本,那么需要运行jmeter-server.bat
tips:
A. 执行机也需要放置jmeter脚本,路径要和控制机保持一致
B. 执行机和控制机的jmeter和jdk版本保持一致
作用: jmeter支持不在GUI方式下运行,可以通过名命令来执行jmeter脚本
参数说明:
命令参数 |
命令释义 |
---|---|
-n |
设置命令行模式 |
-t |
指定jmx脚本路径 |
-l |
指定结果文件路径(jtl或者csv) |
-J |
指定执行日志路径 |
-r |
指定分布式(远程)执行 |
-R |
指定远程(分布式)服务器列表 |
-g |
指定测试结果文件路径 参数为:csv结果文件 |
-e |
设置测试完成后生成测试报告 |
-o |
指定测试报告生成文件夹,文件夹必须为空或不存在 参数为: 报告文件路径 |
-H |
指定代理服务器域名或代理服务器IP |
-P |
指定代理服务器端口 |
注意事项: 切换到jmeter的bin目录然后运行
示例1(测试计划和结果都在bin目录)
jmeter -n -t <目标的jmx文件> -l result.jtl
注:需要添加以下内容到jmeter.properties当中
A. jmeter.save.saveservice.output_format=xml
B. jmeter.save.saveservice.response_data=true
C. jmeter.save.saveservice.samplerData=true
jtl的报告需要通过jmeter界面查看,新建监听器-->查看结果数-->选择一个文件查看
示例2(指定报告路径)
jmeter -n -t <目标的jmx文件> -l report\01-result.csv -j report\01-log.log
示例3(默认分布式运行)
jmeter -n -t <目标的jmx文件> -r -l report\01-result.csv -j report\01-log.log
示例4(指定IP分布式运行)
jmeter -n -t <目标的jmx文件> -R xxx.xxx.xxx.xxxx -l report\01-result.csv -j report\01-log.log
示例5(生成测试报告)
jmeter -n -t <目标的jmx文件> -l report\01-result.jtl -e -o tableresult
tips: tableresult必须是空目录
注:需要还原jmeter.save.saveservice.output_format=csv
1. 通过Jmeter监控服务器性能需要下载插件,插件: 1. JMeterPlugins-Extras 2. JMeterPlugins-Standard
下载地址为: https://jmeter-plugins.org/downloads/old/
下载插件完成后放到jmeter安装mul\lib\ext路径下
2. 下载ServerAgent,地址如下: Tags · undera/perfmon-agent · GitHub
目前发现跑成功之后无法生成图表,可能是由于Jmeter版本太高,后续再尝试
作用:Jmeter自带的http代码服务器实现脚本录制功能,替代badboy等工具
使用方法及步骤:
A. 测试计划-->非测试元件-->HTTP代理服务器
B. 设置端口: 默认8888
C. 选择要录制的线程组
D. 保持KeepAlive
E. 设置本机的请求通过代理去发送(Windows): 控制面板---> Internet选项--->连接--->局域网设置--->勾选“为LAN使用代理服务器(这些设置不用于拨号或VPN连接)(X)”--->地址(本机为127.0.0.1或者具体IP地址)--->端口和第二步设置保持一致
F. 启动HTTP代理服务器
G. 添加如下图所示的筛选规则,然后重新启动HTTP代理服务器,然后抓取需要网站的信息
tips: 控制面板设置好代理服务器后无法连其他网络,除非当前网络自身包含代理,Jmeter HTTP代理服务器启动后可以访问其他网络,如果停止HTTP的代理,记得将控制面板当中的代理服务器取消
Bean Shell是一种完全符合java语法规则的脚本语言,同时他还有自己的语法规则
Java包括: javase, javaee, javame
Jmeter有哪些Bean Shell:
A. 前置处理器-->Bean Shell预处理程序
B. 定时器-->Bean Shell 定时器
C. 采样器-->Bean Shell取样器
D. 后置处理器-->Bean Shell后置处理程序
E. 断言-->Bean Shell断言
F. 监听器-->Bean Shell监听器
1. log打印日志:
1). log.info("");
2). log.error("");
3). System.out.printIn(""); //这个日志打印只显示在控制台中
2. vars表示: JmeterVariables, 操作Jmeter变量---->只能用于当前线程
1). 用户定义变量
2). 正则表达式, Json提取器
3). 定义变量
//获取变量值
Log.info(vars.get(""));
Log.info(vars.get("access_token"));
Vars.put("","");
3. props用于存取Jmeter的全局静态变量---->可以跨线程
//获取全局静态变量
log.info(props.get("jmeter.save.saveservice.output_format"));
props.put("aaa","bbb");
4. prev获取到前面一个取样器返回的信息
//获取前面取样器的值
log.info(prev.getResponseCode());
log.info(prev.getResponseDataAsString());
5. ctx上下文
//获取上下文所有的变量
System.out.printIn(ctx.getProperties());