一、 JMeter介绍
1.1 安装JMeter
下载tar包,解压即可。这里使用的是5.5版本的解压后,在bin目录下找到 jmeter.bat 双击正常双击之后,会出来一个终端如果报错,在bin目录下,打开jmeter.properties文件,找到这一行解开注释,将false改为true
1.2 配置环境变量
把jmeter文件bin目录的位置复制进去
1.3 在cmd终端里 输入 jmeter ,即可打开工具了
关闭工具的方式:叉掉软件或者cmd终端
1.4 JMeter 工具基础配置
1.4.1 字体修改成中文
在jmeter的bin⽬录下,修改⽂件中的内容:language=zh_CN再次重启jmeter,就变成中文了
因为是在配置文件里修改的,之后打开就都是中文的不用每次调整了
1.4.2 字体大小(放大、缩小)
但由于这个无法在配置文件修改,所以每次打开都要自己手动调整
外观也可以自己修改
二、JMeter基本使⽤流程
1)启动JMeter
2)在“测试计划” 右键 下添加“线程组”
线程组:对线程进行管理
3)在“线程组”下添加“HTTP请求”的取样器
4)填写“HTTP请求”的相关请求数据
复制cURL
与postman使用方法类似
点击运行 并保存
再次点击运行启动,能发现这里红色跳动了一下,到底运行成功与否并没有看到效果
5)在“线程组”下添加“查看结果树”监听器
再次点击运行,结果树里出现了一个http请求
点击这个绿色的,可以看到取样器结果
但是这里只有一个请求,也就是模拟了一个用户
6)模拟多用户
首先将之前的请求,全部清除
再到线程组里设置线程数量,模拟多用户
点击运行,发现这里生成了10个请求的取样器结果,也就是 10次并发
三、重点组件
3.1 线程组
控制JMeter将⽤于执⾏测试的线程数,也可以把⼀个线程理解为⼀个测试⽤⼾。
当线程组里有多个请求,若http请求在性能测试运行的过程中出现了接口错误,要采取什么措施?
默认是:继续(无需修改就使用这个)
1) 线程数
线程数:⼀个线程即⼀个测试⽤⼾,设置发送的请求次数(虚拟用户数/并发数 )Ramp-up时间(秒):设置性能测试运⾏时间,单位为秒( 在这个时间内完成性能测试 )循环次数:◦ 配置指定次数:控制脚本循环执⾏的次数◦ 配置循环 永远 :( 一定要配置调度器 )▪ 运⾏时间:脚本执⾏时间▪ 延迟启动时间:脚本等待指定时间才能运⾏
2)Ramp-Up时间
一秒之内发送10次请求,循环次数1次
就会得到10次请求结果
3)循环次数、调度器
注意:取消勾选 永远循环 之后,一定要记得在框框里写上次数,不然启动测试,会自动勾选上永远循环的
一秒内完成发送10次请求,永久循环
点击调度器之后,设置持续时间为2s
这2s内,最终发送多少次请求,我们也不知道。
因为10个请求可能0.1s就完成了,然后循环发送,直到2s结束
通过聚合报告,能看到到底这2s内发送了多少个请求
4)通过结果树查看报错
4-1 请求的ip地址错误
失败:链接 8.137.19.14 这个服务器 超时
发现服务器ip填错了
在请求结果也能看到问题
4-2 请求的路径错误
发现报错401,ip地址没错,路径错了
通过请求头或者请求体查看到问题所在,路径写错了login1
4-3 请求成功
通过 状态码 和 响应数据 来判断是否请求成功
这里响应码 :200 成功
响应数据data:success成功
load time 响应时间(ms)也可以帮助我们判断这个系统的性能
3.2 Http取样器
添加必需的配置:http协议:http/httpshttp主机名/IP: 例如127.0.0.1端⼝:例如80/8080/443等◦ http协议端⼝号 80◦ https端⼝号 443请求⽅法路径(⽬录+参数)内容编码(默认的ISO国际标准,但对中⽂⽀持不友好,可以使⽤utf-8)参数◦ 参数可以拼在路径⾥,也可以卸载参数中◦ POST参数要放到消息体数据中{wd:test}
3.3 查看结果树
一般查看结果树,在自己调试的时候会用到,实际测试不会看结果树取样器结果:统计请求相关的信息Thread Name :线程组名称Sample time: 发送请求时间load time :响应时间Response code :接⼝响应状态码请求:HTTP请求的请求头和请求体的详细信息响应:HTTP响应的响应头和响应体的详细信息
3.4 HTTP请求默认值
同一个系统中的接口,协议、IP、端口号是不变的,但是每次新建请求后又要重新写,特别麻烦
配置HTTP请求默认值
写上博客系统的协议、ip、端口号、内容编码
配置好默认请求值后,即使其他请求去掉 协议、ip、端口号,默认也会是刚才配好的值,所以也能访问。
请求默认值作用于在同一路径下的请求,如果请求里配置了的选项,就以请求中的选项作为参数;如果没有配置,就是默认配置的值。
3.5 HTTP请求头管理器
3.5.1 获取列表时,请求头里的 user_token_header
至于博客列表为啥没能访问,因为还没填写请求方法和路径
配置好博客列表的路径和请求方法后,访问依然报错
响应码:401 (Unauthorized未认证)
打开新的页面,依然是401,无法正常访问
可是正常登录之后,访问列表页就能访问了,到底是哪里出现了问题呢?
重新观察一下正常的从登录到访问列表页的过程。
成功登录之后,返回了一个data这样的数据
在浏览器的列表页 getList这个接口的请求头里,有个user_token_header,它的数值与上面登录时返回的data值 相似
是不是说明,获取列表页请求是因为少了这样一个参数
于是在发送请求时,在请求头里加上这样的参数
果然成功了
3.5.2 jmeter 配置HTTP请求头里的参数
添加相关的数据:例如 user_token_header
然后重新运行,发送请求
发现博客列表的请求发送成功了,而且可以在请求头里看到,带上了刚才配置的HTTP请求头的参数
3.5.3 作用域
jmeter里,配置好的只会作用于同级目录下。
默认情况: HTTP请求头配置后,作用于该整个线程组
如果想作用与单个请求,就把该HTTP请求头配置放在,请求的子集
我们发现 :登录页面的请求头也有了这个参数,这其实是不必要的
所以我们需要将这个请求头只作用于博客列表页
把这个请求头的配置拖到对应的请求这里就好了,这样就只作用在这个博客列表请求了
此时再重新运行,登录页的请求头里就没有那个参数了
3.6 JSON提取器
接⼝响应成功,通过提取返回值对应字段,可⽤于其他接⼝的参数配置
如何提取登录接口返回值里的data数据,作为列表页接口的请求头信息?
细心可以观察可以发现,每次登录请求,响应的数据data里的数值是在变化的,每次都不一样,而我们手动配置的token用于是固定死的,不灵活。而且,要是换一个用户登录,token就不一样了,就又需要手动配置,即使是同个用户登录,token值会过期,也不能一直用下去。
于是我们可以根据响应的数据,把需要的参数和值 提取出来
1)添加JSON提取器
2)JSON 路径操作符
详细可以查看相关博客和资料
这篇写的蛮详细的
提取这里面的data
使用工具 JSON Path Tester ,通过输入JSON 路径操作符 ,来检查是否成功获取到了 json格式里的相关数据
输入正确,会把对应的参数值显示出来
输入错误,会有对应的提示
3) 配置 JSON提取器
将刚写好的 JSON Path(json路径) 放进 JSON Path expressions(json路径表达式)里
Names of created variables : 指的是json提取到的数据保存到这个变量里,也就是变量名
JSON Path expressions:使用json路径表达式,获取到json里数据
更改 HTTP信息头里的值
${token} 就是获取token这个json变量
重新发送请求
这时,登录页响应的数据data,作为博客列表页请求头的参数,发送出去了
可以发现这两个数据是一致的,说明发送正确,成功了
4)作用域
同理,获取用户信息的接口,再加上一个http信息头管理器
但是运行发现还是 401
查看请求头,发现这个值不是我们预期的
发现json提取器提取的是data,而 登录页面 和 列表页面 的响应数据里,都有data
而 json 提取器是和 登录请求和列表请求 同级,所以都作用到了
最开始作用在登录请求上,将登录请求后的响应结果里的 data数据提取出来了token,作为了 列表请求 的请求头参数。
所以 登录 和 列表 的请求 都成功响应了。
但是 随后 接着作用在列表请求,把列表响应的响应结果里的 data数据 提取出来了token,覆盖掉之前的token
从而导致,新的token变了,请求失败
于是调整先后,把json提取的登录凭证放到 登录请求里,这样就只在登录里作用,出了登录页就不会改变了
又因为登录页和列表页获取的token信息一样,可以直接放在同级目录下管理
3.7 用户定义的变量
在列表页点击不同的文章就会进入详情页,不同的详情页取决于唯一的 blogid
也就是说,blogid是会变化的,并且如果删除掉一篇文章后,这个blogid也就失效了,无法请求成功。
于是就需要对详情页的请求参数进行设置。
由于列表页的响应数据就是所有的博客,从而可以把列表响应的blogid提取出来,作为详情页的参数值。
于是乎,使用json提取器 和 http请求头设置
但有一个问题,假设,这里有很多个页面,每个页面都要测试
拿这里的 $.data.[0].id 就要有 $.data.[1].id 、 $.data.[2].id 、$.data.[3].id 等等
添加 用户自定义的变量
添加编辑博客页的请求
加上相关数据
记住 json数据需要 的key 和value 需要加引号
发现失败了
使用网页和postman再发送,对比一下请求头和请求体
发现请求头中的 content-type 不一致
于是再编辑博客页设置请求头参数
将content- type 设置为application/json
运行后,响应成功了
3.8 JSON断言
登录之后,用json断言我们登录响应的结果
当登录成功后,返回SUCCESS,刚好匹配我们预期的SUCCESS ,断言就成功了
通过这个断言可以判断,登录是正常响应的
对于一些总在变化的且有一定规律的数据,可以使用正则表达式来表示。
例如:用户名称、手机号、以及下面这张图的用户的 token信息
又比如说,使用JSON断言 来判断列表页userId是否为1
或者使用正则表达式,来判断userId是否为数字(或者多个数字)
3.9 同步定制器
JMeter同步定时器的作⽤主要在于模拟多⽤⼾并发访问的场景,确保多个线程能够同时执⾏某个操作,以达到 真正的并发效果 。当多个线程同时启动时,它们可能会在不同的时间间隔内执⾏,这样就⽆法达到真正的并发效果。同步定时器的作⽤就是将这些线程的执⾏时间同步,使它们在同⼀时间点执⾏。它可以在多个线程之间 制造⼀定的延迟,直到同时到达指定时间点,再同时执⾏后续的操作。此外,同步定时器可以理解为 集合点 ,当线程数量达到指定值后,再⼀起释放,可以瞬间产⽣很⼤的 压⼒。这样,可以更好地模拟真实的⽤⼾并发访问场景,提⾼测试的准确性和可靠性。在性能测试过程中,为了真实模拟多个⽤⼾同时进⾏操作以度量服务器的处理能⼒,可以使⽤同步定 时器来设置集合点。不过,虽然通过加⼊集合点可以约束请求同时发送,但不能确保请求同时到达服 务器,所以只能说是较真实模拟并发
例如这样的场景,在这个线程组里又5个线程,在1s内执行完成
观察发现,启动后,各个线程陆陆续续开始了,但每个线程并不是同时进行的,有的还没开始,有的已经结束了。
添加同步定时器
现在线程组里有5个线程,就添加并发数为 5(模拟用户的数量)
可以发现,设置同步定时器后,所有的线程都是同步一起开始的
现在线程组里有5个线程,假如我把模拟用户的数量设置为50会怎样??
模拟用户的数量 不能超过 线程组里的线程数,超过会一直等待
既然 模拟用户的数量 不能超过 线程组里的线程数,那能不能小于呢???
为什么 线程1、2、3都完成了,4和5迟迟没有完成呢??
可以,但是 若模拟用户的数量 小于 线程组里的线程数,那最好开启循环,不然会有还未准备的线程在等其他线程。
3.10 事务控制器
事务控制器平时用的比较少,基本上是单接口的性能测试
一个接口看做成一个事务
这里有五个事务
添加事务控制器
可以把多个接口,放入一个事务里
例如:把登录和用户这两个接口放到一个事务里
在聚合报告可以看到这样的数据
这里的数值大部分都是毫秒为单位
最常使用参考的数据是 95%、99%请求的响应时间
3.11 csv数据文件设置
以登陆接⼝为例,当我们执⾏登陆接⼝的性能测试时,⼿动配置了⽤⼾名和密码为固定的username和 password,然⽽实际使⽤中不可能只有⼀个⽤⼾登陆。为了模拟更真实的登录环境,我们需要提供更多的⽤⼾username和password来实现登录操作。添加⽅式:线程组⸺配置元件⸺CSV数据⽂件设置
在登录请求这里,之前是写死的用户名和密码
zhangsan 123456
现在使用变量${username} ${password}来代替
使用excel表格创建csv文件,写好用户名和密码
运行之后,发现的确使用了csv文件的多个账号登录了
3.12 HTTP Cookie管理器
HTTP Cookie管理器像Web浏览器⼀样存储和发送Cookie。如果HTTP请求并且响应包含cookie,则 Cookie管理器会⾃动存储该cookie,并将其⽤于将来对该特定⽹站的所有请求。每个JMeter线程都有⾃⼰的"cookie存储区"。因此,正在测试使⽤cookie存储会话信息的⽹站,则每个JMeter线程都将拥有⾃⼰的会话。此类Cookie不会显⽰在Cookie管理器显⽰屏上,可以使⽤"查看结果树监听器"查看。缓存配置可选择standard(标准)或compatibility(兼容的),当然也可以⼿⼯添加⼀些cookie.添加了HTTP Cookie管理器后,会⾃动存储并发送Cookie
四、Jmeter 插件管理工具
并发测试测试中,假设期望最高并发量为10000,但是测试的时候不能一上来就直接测试10000,有可能这个就是系统的极限了,一上来就直接卡死崩溃了。
所以 并发测试都是 一点一点往上去加的
1000
2000
5000 ...慢慢加到期望的数值,也有可能在期望数值之前就已经达到极限了
普通修改就是在线程组里修改线程数量
但是这样并不能直观看到不同线程数并发时的区别和效果
4.1 Jmeter插件管理工具下载
下载后放到jmeter的lib的ext路径下
之后,jmeter工具就可以支持安装插件了
关闭jmeter然后重启
右上角有一个像蝴蝶翅膀的东西,就说明成功了
4.2 下载 监听器插件、线程组插件
点击小蝴蝶图标,在available plugins 里面搜索 page data extractor(监听器插件)、custom thread group(线程组插件)
安装后重启
安装成功之后,就会发现多了这些工具
4.3 Stepping Thread Group 梯度压测线程组
This group will start:启动多少个线程,同线程组中的线程数First, wait for:等待多少秒才开始压测,⼀般默认为0Then start:⼀开始有多少个线程数,⼀般默认为0Next,add:下⼀次增加多少个线程数threads every:当前运⾏多⻓时间后再次启动线程,即每⼀次线程启动完成之后的的持续时间;using ramp-up:启动线程的时间;若设置为5秒,表⽰每次启动线程都持续5秒thenhold loadfor:线程全部启动完之后持续运⾏多⻓时间finally,stop/threadsevery:多⻓时间释放多少个线程;若设置为5个和1秒,表⽰持续负载结束之后每1秒钟释放5个线程例如这个
五、性能测试报告
5.1 使用命令行生成jemter性能测试报告
Jmeter -n -t 脚本⽂件 -l ⽇志⽂件 -e -o ⽬录-n : ⽆图形化运⾏-t : 被运⾏的脚本-l : 将运⾏信息写⼊⽇志⽂件,后缀为 jtl 的⽇志⽂件-e : ⽣成测试报告-o : 指定报告输出⽬录发现在我们指定的test文件夹下,已经生成好了测试报告的网页文件双击index.html
5.2 测试报告的内容
还有一些图表可以查看
5.3 分析性能测试报告
5.3.1 响应时间
性能测试报告,只能发现问题,并不能解决问题,测试人员需要会使用性能测试工具进行性能测试,并分析。把测试报告给开发人员,他们来进一步解决问题。
在这里问题很明显的是响应时间,博客列表的平均响应时间,达到了9秒
分析:
1)博客列表里有很多博客,而底层我们写的是遍历完所有的博客,也就是一次全部展示完,也就是全表查询。随着博客的增加,全部遍历完的响应时间就会增大。
2)系统不稳定,有时快,有时慢。随着并发压力变大,而慢慢变慢,导致响应时间增大。
所以,在展示的时候,可以分页展示,一次展示10个,用户往下滑动继续翻页的时候,再继续展示接下来的页面。