软件测试 - 性能测试 (实战 - 基于场景的性能测试-博客系统)(⼯具 - JMeter )
一、 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 路径操作符
详细可以查看相关博客和资料
jsonpath :从入门到精通-CSDN博客
这篇写的蛮详细的
提取这里面的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插件管理工具下载
Install :: JMeter-Plugins.org
下载后放到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个,用户往下滑动继续翻页的时候,再继续展示接下来的页面。