Jmeter接口测试、性能测试详细介绍
下面主要就是讲一下Jmeter工具的用法,用法非常简单,比起loadrunner不知道简单多少,并且开源免费~~
1、接口简介
接口定义
接口:
就是数据交互的入口和出口,是一套标准规范。
接口(硬件类接口)
是指同一计算机不同功能层之间的通信规则称为接口。比如USB接口。
接口(软件类接口)
前后端共同遵守的一套数据交互的规范
接口优点:
前后端开发相对独立,都遵循文档规范就可以了,提高了效率。
扩展性灵活,人员变动不受太大影响。
2、接口测试简介
接口测试,就是测试后端的实现是否符合接口规范。
测试都测什么?
一是程序的功能、安全性
二是效率(性能)
怎么测?
模拟客户端向服务器发送数据,然后查看响应。
比如说:登录功能的接口,一般情况是发送一个带有用户名和密码数据的请求到后台,后台再返回一个json格式数据,比如前端需要显示用户名,那么后台就要返回一个用户名。接口测试就是要测返回的这个数据是否符合接口文档的格式,内容是否正确等。
接口测试分类:
web接口测试(B\S架构)
一种是服务器接口测试(公司自己的程序)
一种是第三方接口测试(别的公司的接口,比如微信支付接口)
模块接口测试(C\S架构)
3、环境搭建
测试接口的插件/工具:
火狐浏览器:RESTClient
谷歌浏览器:POSTman
Java实现的测试工具:Jmeter
安装好这些工具,方便后期使用,下面简单说了一下RESTClient、Postman如何安装,Jmeter会在后面重点说明。
一、火狐插件RESTClient安装
- 打开火狐浏览器,点击右侧的选项按钮,选择附加组件
2.搜索RESTClient
3.搜索到后点击进去,点击添加到firefox
二、postman工具
chrome浏览器被屏蔽了,可能搜不到postman,直接去网上下载一个插件rar包,解压。点击扩展程序,加载已解压的扩展程序。
这种方式的话,一定要注意chrome浏览器版本和postman版本有对应关系,比如:
chrome的65.0.3311.4版本对应postman插件的4.1.3版本。
再或者可以下载一个postman.exe文件,安装到电脑中。
使用postman做简单的接口测试:
get方法:
打开postman,比如查询功能,像下面这个截图,默认是GET方法,后面输入链接,点击send,下面就返回了数据,检查返回的数据和状态字,都是正确的。
POST方法:
示例是参考这个api文档:
里面有一个接口为:
用postman测试,就选择POST,输入链接:https://cnodejs.org/api/v1/accesstoken
然后点击下面的key,输入accesstoken,再点击value,输入你的accesstoken,就可以查询到结果:
点击下图标红的地方,可以切换输入post数据的风格:
4、RESTful风格
开发测试时,大家的都会遵守的一些默认的规范,这些约定俗成的,大家习惯的作法,非强制性的。RESTful风格也是这样一种规范。
RESTful具体规范内容:URL实现方式、提交数据的实现方式、响应的数据的实现方式等。
接口一般就是和后台交互数据的,针对数据常用的就是增删改查操作,RESTful针对增删改查都有哪些规则呢?
增加数据(比如注册,向后台新增数据):
- URL:应该使用POST方式
- 提交数据方式:
方式1:URL?key=value&key1=value1
方式2:json格式
3.响应的数据:
状态码200/201+刚才添加的记录
查询数据(比如搜索):
- 一般是GET方式
- 提交数据方式:
常用方式1:URL?key=value&key1=value1
3. 响应的数据:
状态码200/201+查询到的数据
修改数据:
1. 一般是POST/PUT方式
2. 提交数据方式:
方式1:URL?key=value&key1=value1
方式2:json格式
3. 响应的数据:
状态码200/201+修改后的数据
删除数据:
1. 一般是GET/DELETE方式
2. 提交数据方式:
方式1:URL?key=value&key1=value1(常用)
方式2:json格式
3. 响应的数据:
状态码200/204+无
5、Json说明
Json是一种数据载体,是一种轻量级的数据交换格式。常见的还有html、xml等,而互联网本质就是各种数据传输,数据传输的数据载体就可以用json、html、xml等。
相比较来说,json描述更简洁,如果数据量小的话,用json很方便,效率更高。
json语法:
- 键值对格式:{‘key1’:’value1’, ‘key2’:’value2’, ‘key3’:’value3’}
- 数组/列表格式:[’value1’, ’value2’, ’value3’]
- 组合格式:{‘key1’:[1,2,3], ‘key2’:[4,5,6], ‘key3’:’value3’}
[{‘key1’:’value1’, ‘key2’:’value2’, ‘key3’:’value3’}]
6、Jmeter简介
Jmeter是Apache组织开发的基于Java的开源的压力测试工具。可以模拟高并发和多次循环的测试场景,能够对HTTP和FTP服务器进行压力和性能测试, 也可以对任何数据库进行同样的测试(通过JDBC),可移植性
Jmeter的作用:
- 接口测试
- 性能测试:内在算法,执行效率(响应时间)等
- 压力测试:外在的压力(最多并发用户数,负载测试)
- web自动化测试
- 数据库测试
- java程序测试
Jmeter优点:
- 支持多协议:http、https、ftp、ftps等
- 开源、免费
- 小巧并且功能强大
Jmeter缺点:
- 不支持IP欺骗
- 不支持前端测试
7、Jmeter环境搭建
Jmeter是基于java开发的,所以要运行Jmeter,必须要先安装java环境(百度一下就知道怎么安装了),然后下载Jmeter,去apache官网下载:
https://downloads.apache.org/jmeter/binaries/
下载的时候要注意看这句话:Apache JMeter 5.2.1 requires Java 8+,Apache Jmeter版本和java版本的对应关系
Jmeter下载下来后,解压,长这样:
双击进入bin文件夹,找到ApacheJMeter.jar文件,双击打开就启动了Jmeter工具。
能启动起来看到类似下面这个图的界面,环境就ok了。
安装好之后,配置环境变量,win7:计算机右键->属性->高级系统设置->环境变量->下面的系统变量中,新建一个变量,变量名:JMETER_HOME,变量值:你的Jmeter安装路径比如:D:\Jmeter\apache-jmeter-3.1
然后修改Path,后面新增一个%JMETER_HOME%\bin;注意如果前面有别的环境变量,要有分号隔开。再增加几个环境变量,都是后续会用到的:
%JMETER_HOME%\lib\ext\ApacheJMeter_core.jar;%JMETER_HOME%\lib\jorphan.jar;%JMETER_HOME%\lib\logkit-2.0.jar
8、Jmeter使用
8.1 Jmeter发GET请求
用一个简单的小例子,说明一下使用Jmeter发送一个get请求的操作步骤:
第一步:打开Jmeter后,输入一个测试用例的名字,比如测试名称输入“测试计划1_helloworld”,然后ctrl+s保存:
第二步:右键点击左侧的“测试计划1_helloworld”,选择“添加”--Threads--线程组,输入一个名字,比如“线程组01”,保存。
第三步:右键点击“线程组01”,点击添加--Sampler--HTTP请求
第四步:上面添加了一个http请求,接下来就是构建http请求了,输入一个http请求的名字,比如“HTTP请求01_查询最新新闻”,下面主要填写如图圈红部分,服务器名称或者IP,端口号,协议,方法,编码,以及路径。
注意:这里的服务器名称或者IP,端口号是你要测试的网站的IP地址和端口,一般是公司的某台服务器,公司会提供。协议,一般就是HTTP和HTTPS,方法常用的get、post等,编码一般写utf-8就可以,路径就是你的测试路径,我这里直接写的知乎的一个开放API路径,如果上面有写了服务器和端口,下面这个路径是可以省略前半部分的。根据实际情况写即可。
比如测试这个接口:https://news-at.zhihu.com/api/4/news/latest,下面这两种写法都可以:
第五步:上面构建好了要发送的请求,接下来要添加一个监听器,在发送请求的时候会把结果记录下来。右键测试计划--添加--监听器--察看结果树
第六步:点击工具栏里面的绿色倒三角,就执行了HTTP01请求,察看结果树里面可以看到响应结果。
8.2线程组
进程概念:正在执行的程序
线程概念:线程是程序执行时的最小单位,它是进程的一个执行流,是CPU调度和分派的基本单位。一个进程有多个线程。比如迅雷下载,每一个下载任务就是一个线程。
线程组:按照线程性质被线程执行的分组。
并发执行:多个线程同时执行,每个线程结束的顺序和开始的顺序不一定一致。
顺序执行:按照线程的启动顺序挨个执行,一个线程执行结束再开始另一个线程。
8.2.1 并发执行
在Jmeter中,如何设置并发执行?
拿8.1讲过的例子来说,如下图:
进程可以认为是测试计划,线程组就是线程组01,打开线程组,可以看到下图所示的线程属性,可以设置线程数,加入改成2,再执行一次:
执行结果就会看到两个线程结果:
结果1:
结果2:
这样设置就等同于两个用户并发执行了~
8.2.2 顺序执行
那么顺序执行呢?
右键点击测试计划,可以看到有一个“独立运行每个线程组”复选框,勾选上,然后我再添加一个线程组,这样运行后,就可以看到是挨个线程组运行了:
运行结果:
8.2.3 线程组-Ramp-Up Period(in senconds)
上面讲了线程数,表示用户数。线程属性中还有一些其他值,点击线程组03,如下图:
Ramp-Up Period(in senconds):这个值的意思是在多少时间之内执行完全部线程。单位是秒。比如这里写10,线程数改为3,那就是10s之内运行3个线程,平均3秒钟执行一个。
8.2.4 线程组-循环次数
循环次数:单个用户循环的次数。如果改成2,线程数为3,那就是3个用户将这个线程组中的请求分别执行2次。循环次数勾选永远的话,就是一直执行,直到点击停止按钮:
8.2.5 线程组-调度器
调度器有两种用法:
第一种:
勾选调度器,输入持续时间和启动时间,点运行。
持续时间意思是持续发送请求的时间,6秒钟之内一直发。
启动延迟:意思是点击运行后,延迟几秒中再发请求。
第二种:
就是下面的启动时间和结束时间。可以输入具体的启动时间值和结束时间值。
ps:使用调度器的时候,上面的循环次数勾选“永远”。
8.2.6 setUp和tearDown
前面讲顺序执行的时候,勾选“独立运行每个线程组”,线程组就会按照顺序依次执行,但是这里还有两个特殊的线程组,setUp和tearDown。setUP线程组会在所有线程组执行前执行,tearDown线程组在所有的线程组执行完毕后执行。
如何添加?
右键单击测试计划--添加--Threads--setUp Thread Group/tearDown Thread Group
setUp线程组:一般可以用来加载程序运行时需要的资源
tearDown线程组:可以用来放一些保存运行结果的代码
8.3POST请求
如何用Jmeter实现用户注册?
大体步骤和上面的类似,创建一个线程组,线程组中添加一个取样器sample--http请求,然后修改服务器名称或IP,修改方法为POST,修改路径,接下来就是修改body内容,一般是json数据、Form表单、xml或者JavaScript等。
如果测试注册功能呢?拿下面这个例子来说:
前三步和发GET请求是一样的,第四步,点击Parameters中的添加按钮,输入键值对即可:
第四步也可以点击Body Data,直接输入内容:
如果查看结果树里面的内容过多需要清除的话,可以使用工具栏中的:
这里还需说明一个HTTP请求头里面的概念:Content-Type。
应该都知道,发post请求是需要有数据的,但是数据的格式是什么,要怎么告诉浏览器呢?就是请求头里面的“Content-Type”键。
之前用Jmeter,没有修改Content-Type,但是也都正常执行了,那是因为Jmeter会有默认的Content-Type,那就是:x-www-form-urlencoded,如果你的接口刚好使用的是这种格式,就没问题。但是如果你的接口只能接受json数据,这样就会出问题。
当Content-Type为默认x-www-form-urlencoded时:
如果是get请求,浏览器用x-www-form-urlencoded的编码方式把form数据转换成一个字串(name1=value1&name2=value2…),然后把这个字串append到url后面,用?分割,加载这个新的url;如果是post请求,浏览器把form数据封装到http body中,然后发送到server。
比如图:
如果你的接口是需要其他格式的:比如:”application/json”、”application/xml”、“application/javascript”,Jmeter中应该怎么去修改呢?
选中“测试计划”,右键,选择“添加”--“配置元件”--“HTTP信息头管理器”,点击“添加”,输入键值对即可,如下图:
需要注意的是:注释可以不写,Content-Tpye的值为:
application/json;charset=utf-8。这里面的分号必须是英文的。
charset=utf-8的作用是为了保证浏览器各种字符都可以识别。
json也可以修改为xml或者JavaScript,看自己的需求到底是什么。
请求头如果写的是json,那么你对应的请求中的Body Data就需要是json格式。
8.4 HTTP请求默认值
我们测试的时候,如下图的服务器名称或者IP,以及端口号,HTTP请求的协议,编码格式等一般都是一样的,此时我们可以将这些数据抽离出来,放到HTTP请求默认值中,这样你新建HTTP请求的时候可以不用写这些重复的值了。
如何抽离?
在测试计划1_helloworld这里右键点击添加--配置元件--HTTP请求默认值,将相同的内容添加到这个页面中保存即可。
8.5 Jmeter参数化
参数化的概念和其他的自动化测试中的参数化概念一样,就是为了执行批量操作,比如批量注册,批量登录,用户名和密码需要很多不同的值,此时就可以用到参数化。
8.5.1方式一:CSV DATA Set Config
CSV DATA Set Config是Jmeter的一个参数化组件,通过这个组件可以动态获取并设置数据,实现类似批量操作。
拿登录来说,假如要测试同时5人登录,那么就需要5个账号密码。如何实现参数化?
1.首先要编写登录测试用例,设置循环次数为5次,post需要发送的账号和密码先填空。
2.编写一个外部文本文件,存储要登录的5个人的账号密码
3.Jmeter添加一个参数化组件CSV Data Set Config,每次循环时都读取文本文件的一行数据,将数据的账号密码字段分别填入post数据中。
步骤:
1、新建一个线程组,循环次数为5
2、添加HTTP请求,写上路径、方法以及BodyData,BodyData只需要写键
3、添加一个CSV组件:右键单击“线程组”->添加->配置元件->CSV Data Set Config。
filename:参数文件的路径
file encoding:编码格式,要注意你的参数文件必须是utf-8无BOM格式。
Variable Names:这项内容,可以认为是列名,或者给参数起的名字,多个名字用逗号隔开。
Delimiter:这里默认有一个逗号,表示你的参数文件里面的参数用逗号分隔的。
我的dataLogin.txt的内容是这样:
我需要用到两个参数,所以Variable Names我写两个变量名;dataLogin.txt中参数用逗号分隔的,所以Delimiter中写逗号。根据实际情况改即可。
4、去修改HTTP请求中的Body Data:name=${username}&passwd=${pwd}
要注意格式必须是${变量名}
如果你的Body Data需要是json数据,大概写法是这样:
{
”name”:”${username}”,
“passwd”:”${pwd}”
}
之后运行试试吧,应该是会出来5个结果,每个结果对应的是一个参数对应的返回信息。
ps:循环次数也可以大于5次,大于5次的时候,就是把参数用完后再从头开始使用。
ps:除了可以修改循环次数为5次,线程数改为5,也会依次执行每组参数。
8.5.2方式二:不用外部文件
步骤:
1、再新建一个线程组,此时线程数设置为3,添加一个HTTP请求,和上面的第2步一样。
2、右键点击线程组->添加->前置处理器->用户参数。
输入名称,名称就是变量名,用户是代表每个用户的变量值。下面四个按钮可以添加变量、删除变量、添加用户、删除用户。
目前我这里写了3个用户。
3、第三步和CSV的方法的最后一步一样,去修改POST的Body Data。
name=${username}&passwd=${pwd}
8.5.3方式三:用户自定义变量
还是直接举例来说吧,例如如下接口:
以下 api 路径均以 https://cnodejs.org/api/v1 为前缀
1、get /topics 主题首页
接收 get 参数
- page Number 页数
- tab String 主题分类。目前有 ask share job good
- limit Number 每一页的主题数量
- mdrender String 当为 false 时,不渲染。默认为 true,渲染出现的所有 markdown 格式文本。
2、get /topic/:id 主题详情
接收 get 参数
- mdrender String 当为 false 时,不渲染。默认为 true,渲染出现的所有 markdown 格式文本。
- accesstoken String 当需要知道一个主题是否被特定用户收藏以及对应评论是否被特定用户点赞时,才需要带此参数。会影响返回值中的 is_collect 以及 replies 列表中的 is_uped 值。
示例:/api/v1/topic/5433d5e4e737cbe96dcef312
步骤一:新建一个线程组:线程组03_用户自定义变量,添加两个HTTP请求,第一个请求测试主题首页,服务器名称或者IP应该是:cnodejs.org,路径:/api/v1/topics;第二个详情测试主题详情,服务器名称或者IP是:cnodejs.org,路径:/api/v1/topic/5433d5e4e737cbe96dcef312;
步骤二:可以看出来,步骤一中的路径“/api/v1”这一部分是重复的,不只是这两个请求是这样,所有的请求都是以/api/v1开头,针对这个重复部分,可以提取出变量,以后可以不用重复写这部分,如果这部分需要修改,那么也只需要改一个地方即可。所以第二步就是添加一个用户变量来保存这部分内容,在测试计划的地方右键->添加->配置元件->用户自定义的变量,点击添加按钮,输入变量名和值。如图:
第三步就是使用这个变量替代HTTP请求中的重复部分:
改好之后运行就可以看到结果了,和不使用全局变量是一样的结果只是这样的话更方便,如果路径长的话,也不用担心路径写错。
运行的时候,以前的线程组可以先禁用,禁用后再运行就只会运行没有被禁用的。在线程组或者HTTP请求上右键,点击禁用即可。
另外还有一点,就是查看结果树中,响应数据默认的是显示text形式的结果,这个示例的结果是json,用text显示就非常不好看,可以修改一下显示的方式:
第三种方法就说完了,这个方法用的地方不是很多,一般只用来存储全局使用的变量,了解下即可。
8.5.4方式四:使用函数参数化
比如
获取网易新闻API
请求方式:POST
请求地址:https://api.apiopen.top/getWangYiNews
如果要查询多页,那么就需要每次只修改page即可,像这样:
https://api.apiopen.top/getWangYiNews?page=1&count=5
https://api.apiopen.top/getWangYiNews?page=2&count=5
https://api.apiopen.top/getWangYiNews?page=3&count=5
此时就可以使用一个函数来代替页码。步骤:
1、依然是新建一个线程组,新建一个HTTP请求,将各项内容填好,Body Data的内容是:page=1&count=5
2、然后在菜单栏的“选项”里面有一个“函数助手对话框”,点击它,或者点击工具栏的倒数第二个按钮,或者是快捷键Ctrl+Shift+F1
3、弹出函数生成对话框后,选择一个功能,我们选__counter,函数参数,第一个参数可以写FLASE,表示这个计数器是所有的线程共用一个,如果是True,表示每一个线程使用一个计数器。然后我们点击生成,就会在左侧的框中生成一个字符串,复制这个字符串:
4、将上面的字符串粘贴到Body Data中:page=${__counter(FLASE,)}&count=5
5、然后我们将这个线程数设置为2,循环次数设置为3,运行测试下,测试结果看到请求中的POST数据的page值是从1-6变化的
如果__counter()函数的第一个参数设置为True,结果应该是page会从1-3变化,2个用户,所以会有2个1-3.
这里还有很多其他的函数可以使用,甚至可以自定义函数,后期再继续学了。总体来说,使用函数参数化的用法就是:${函数名(参数)}
8.6直连数据库
jmeter本身没有提供连接数据库的功能,需要使用第三方jar包。这里使用mysql数据库举例,使用方式:
1、在测试计划的属性下面有一个Add directory or jar to classpath(添加文件夹或jar包),点击添加,选择mysql连接java的jar包。
我的放到了:D:\Jmeter\apache-jmeter-3.1\self\mysql-connector-java-5.1.35-bin.jar
2、配置数据库连接信息:在测试计划处右键->添加->-配置元件->JDBC Connection Configuration
Variable Name:自定义参数名字,在JDBC Request中会用到;
Database URL:jdbc:mysql:// 数据库IP地址:数据库端口/数据库名称;
(jdbc:mysql:相当于一个协议,类似http:一样,固定这样写,就是告诉Jmeter是mysql数据库,如果是别的数据库,mysql改一下即可,比如jdbc:sqlite:)
(数据库名称后面可以加参数:?useUnicode=true&characterEncoding=utf-8)
JDBC Driver Class:com.mysql.jdbc.Driver;mysql数据库的驱动
Username:数据库用户名;
Password:数据库密码;
3、然后在线程组中添加一个JDBC请求:右键线程组->添加->Sampler->JDBC Request
这里要注意添加的是JDBC Request,不是HTTP请求,JDBC Request属性中:
Variable Name:是第二步里面的Variable Name,必须写一样。
Query Type: 目前常用的就是Select Statement(sql语句是select的时候选择这个);sql语句是删除、修改、添加的时候选择Update Statement
下面的文本框中写你的sql语句。
这样3步完成,运行就可以在察看结果树中看到select的结果了。
查到了数据库的内容,接下来就是使用这些内容了。
还用之前参数化时用的接口api.apiopen.top/developerLogin
4、先去修改一下JDBC Request里面的查询语句为select name,pwd form login,然后在下面变量名的位置,写上两个变量
Variable name:就是存储的数据库取出来的值,username对应name,pwd对应pwd。
5、然后添加一个HTTP请求:api.apiopen.top/developerLogin,将上面保存的值传给HTTP请求的name和pwd
Body Data中写:name=${username_1}&passwd=${pwd_1}
需要注意的是,username保存的是查出来的所有符合条件的name值,想要取其中的某一个值,需要后面跟下划线+数字的形式表示你想使用第几条数据。
运行就可以看到结果了。
8.7 Debug用法
还是接着上面的来说明Debug的功能,在我们的HTTP请求或者JDBC Request请求上右键,添加->后置处理器,选择Debug PostProcessor
然后运行,可以看到运行结果多了一个Debug PostProcessor
从结果看,可以看到密码都被存到了pwd_1、pwd_2、pwd_3中,并且pwd_#可以用来表示总共有几条记录。
8.8 Jmeter关联_xpath提取器
关联,意思是两个请求有关联性,比如一个请求的结果需要用到另一个请求中。上面讲到的从数据库取出数据给HTTP请求就是一种关联。
现在我们新建两个HTTP请求,一个请求百度首页,一个请求搜狗首页,将百度首页响应回来的title中的内容提取出来,去搜狗里面搜索,这里我们使用xpath提取器,步骤:
1、新建两个HTTP请求,如下图:
2、在HTTP请求_访问百度那右键,选择添加->后置处理器->XPath Extractor,
一般在HTTP请求结束后需要做的操作都放到了后置处理器中,我们现在需要把访问百度的请求发送完之后,利用xpath拿到响应中的内容,所以去后置处理器中添加XPath Extractor控件,这个控件主要需要注意3个点:
Use Tidy:因为是返回的是html,必须勾选Use Tidy。
引用名称:就是变量名,你取出你想要的值后放到变量中。
XPath query:写xpath表达式
缺省值:意思是没有找到xpath就用这个值替代。
3、将HTTP请求_访问搜狗的请求的路径改成:/?query=${queryText},这个是第2步中的xpath变量名。
然后运行,可以看到结果:
8.9 Jmeter关联_正则表达式
上面8.8节是使用xpath提取器提取信息使用,事实上也可以使用正则表达式,上面的第2步,改成:在HTTP请求_访问百度那右键,选择添加->后置处理器->正则表达式提取器
引用名称:依旧是变量名
正则表达式:就是你需要提取的内容,()括号表示提取字符串中的部分值,()前后是提取的边界内容。正则表达式如果不懂,需要单独学习一下。
模板:正则表达式的提取模式。这里是固定格式:$数字$,
如果正则表达式有多个提取结果,则结果是数组形式,模板$1$,$2$等等,表示把解析到的第几个值赋给变量;从1开始匹配,以此类推。
若只有一个结果,则只能是$1$;
匹配数字:
正则表达式匹配数据的结果可以看做一个数组,表示如何取值:0代表随机取值,正数n则表示取第n个值(比如1代表取第一个值),负数则表示提取所有符合条件的值。
示例2:
比如我先拿到网易新闻的热点新闻标题,然后到搜狗中去搜索。
1、添加HTTP请求,网易新闻API请求,服务器名称:api.apiopen.top,路径:/getWangYiNews
2、添加正则表达式提取器,
引用名称为:queryText;
正则表达式为:"title":"(.*?)"
模板:$1$
匹配数字:1
3、添加HTTP请求,搜狗或者百度等,路径为:/?query=${queryText}
运行即可。
如果从标签语言中,比如html或者xml,一般用xpath提取器即可,如果是文本的话,用正则表达式。
Jmeter添加聚合报告:
聚合报告可以看到发送请求的响应时间、吞吐量、错误率等
添加方法:右键测试计划->添加->监听器->聚合报告
8.10 Jmeter断言
断言意思就是判断你程序响应结果是否正确。请求成功并不代表结果正确,所以增加断言机制提高正确性。类似于LR中的检查点。
HTTP请求中断言主要包括:
- 断言状态的响应码
- 断言响应的内容
- 断言响应内容的长度
- 断言响应的时间
下面挨个讲解如何添加断言
8.10.1 响应码和返回内容断言
前面有添加一个搜狗首页的HTTP请求,继续拿这个请求举例,或者拿百度请求举例都一样。在请求上点右键,添加->断言->响应断言:
出来如下图,下图我添加了一个要测试的模式,写了一串字符串“搜狗搜索引擎 - 上网从搜狗开始”,Apply to选择“Main Sample only”,要测试的响应字段选择“响应文本”,模式匹配规则选择“Substring”。这样意思就是说我想判断我的响应文本是否包含“搜狗搜索引擎 - 上网从搜狗开始”字符串。
详细说明每一项内容:
响应断言页面,第一块内容是名称和注释,跟其他页面一样,起个名字,写个注释。
Apply to(断言应用的范围):
- Main sample and sub-samples – 可以同时应用到主取样器和子取样器。
- Main sample only - 只能应用到主取样器。
- Sub-samples only - 只能应用到子取样器
- JMeter Variable Name to use –应用到指定名称的变量(对指定的变量的值进行提取)
取样器就是sampler,在线程组右键->添加->sampler->HTTP请求,这里的sampler除了包含HTTP请求还包含很多其他的请求,FTP、JDBC等等,这些都叫取样器。
我们这里只添加了一个取样器,没有添加子取样器,那就默认选中的Main sample only就可以了,不需要修改。
要测试的响应字段:
- 响应文本:察看结果树中的响应数据,不包括Response Headers
- Document(text)和URL样本不常用,暂不关心。
- 响应代码:就是返回的响应码,比如200、404
- 响应信息:即Response message: OK,在察看结果树中可以看到。
- Response Headers:响应头部。
- Ignore Status:一个请求有多项响应断言时,忽略某一项断言的响应结果,而继续下一项断言。即在某个断言检查前,先将取样器的状态设置为成功。注意,因为改设置会清除任何之前的断言失败的影响。所以,请确认只在第一个断言设置该选项。
要测试的模式:
模式匹配规则在下面讲,这里先说要测试的模式,点击下面的添加,就可以添加一个模式,这个模式可以是一个正则表达式,也可以是纯文本,比如想要测试返回的信息是否包含“搜狗搜索引擎 - 上网从搜狗开始”,就写“搜狗搜索引擎 - 上网从搜狗开始”这段文本即可。想测试返回的响应数据是否符合<html></html>格式,中间的内容是什么不重要,那么可以写<html>.*</html>
模式匹配规则:
上面说了要测试的模式可以是正则表达式,也可以是纯文本,那怎么区分你写的<html>.*</html>是正则表达式还是纯文本呢,就是在模式匹配规则选择。
- 包括:表示你用的是正则表达式,只要返回的响应内容包括你写的测试模式即可。
- 匹配:表示你用到是正则表达式,需要返回的内容完全匹配你写的测试模式。
- Equals:表示你写的是文本,需要响应的内容和你写的测试模式完全一样。
- Substring:表示你写的是文本,响应的内容包含你写的测试模式的内容就可以。
否:就是不包含、不匹配的意思了。
在运行之前,先添加一个断言结果:
HTTP请求的地方右键->添加->监听器->断言结果
ps:这个断言结果也可以拉到线程组同级,运行的时候就会保存所有的线程组的断言结果。
添加后,运行,查看结果。
下面我们改一下响应断言的内容:改成判断响应信息,要测试的模式写小写的ok。再看断言结果:
这里提示:Test failed: message expected to contain /ok/
就是说返回的内容不包含ok。
然后我们看察看结果树里面,也会有报错信息,并且Response message就是OK呀,为什么报错说不包含ok呢,这就说明了“要测试的模式”是区分大小写的,改成大写的OK,再测试就可以了。
8.10.2 断言返回内容的长度
在HTTP请求的地方右键->添加->断言->Size Assertion
名称和注释不用说了,apply to在上面的断言响应内容也说过了,“Response Size Field to Test”类似于上面讲的“要测试的响应字段”
size to assert:这里想要判断返回的全部响应内容大于100字节,就如图那样写,想要判断响应信息(不包含头)等于1000字节,就将比较类型选择第一个,字节大小改成1000即可。很简单。
8.10.3 断言响应时间
在HTTP请求的地方右键->添加->断言->断言响应时间
修改持续时间的值即可,注意单位是毫秒。
8.11Jmeter集合点
集合点:Jmeter内置组件之一,可以启动多个用户,让多个用户在同一刻去访问服务器。模拟高并发,测试服务器性能。
比如我还是在访问搜狗的HTTP请求中添加集合点,右键HTTP请求->添加->定时器->Synchronizing Timer
设置集合点的前提是要有多个线程数,我们把线程数设置为10。
Number of simulated Users to Group by:这个意思是几个为一组,比如说我写的3,那就是3个一组并发执行,先执行3个再执行3个再执行3个,最后剩下1个了,没办法组成3个,就会一直等待,到了超时时间自动退出。所以这里我们尽量写成和线程数一样或者能被线程数整除的数字。
Timeout in milliseconds:就是超时时间,单位毫秒。默认写的0,表示无限等待,不设置超时。
8.12 Jmeter函数
函数是Jmeter中封装的最小单元,是一些功能实现,前面用过__counter(),就是一个函数。
参数使用的操作步骤还是1、打开函数助手;2、选择函数;3、修改参数;4、生成并拷贝结果去使用。
下面是常用的函数以及用法:
__counter():计数器
__time():获取时间的函数
__random():生成随机数的函数
__CSVRead():读取CSV文件的数据,和CSV DATA Set Config类似。
__setProperty():设置属性
__property():获取属性
__time()函数:
${__time(yyyy/MM/dd HH/mm/ss,)}:取当前的年月日 时分秒
__time()的第一个参数可以:yyyy/MM/dd HH:mm:ss(年/月/日 时/分/秒)
也可以只有年月日,yyyy/MM/dd
或者只有时分秒,HH/mm/ss
格式也可以变化,比如yyyy.MM.dd,注意大小写敏感。
第二个参数就是将当前的时间值存到哪个变量名中。
__Random()函数:
Random()函数是取一个随机数的意思,有三个参数,前两个参数是随机数的取值范围,第三个参数是变量名,将取到的随机数放到哪个变量中。
__CSVRead()函数:
从CSV文件读取一些数据,进行批量操作
上面讲参数化的时候,说过多用户同时登录的操作,用__CSVRead()函数如果实现呢?
接口链接:https://api.apiopen.top/developerLogin
1、添加一个HTTP请求,线程数设置为3,新建一个文件保存接口需要的参数:
2、然后使用函数生成工具,找到__CSVRead()函数,
两个参数,第一个参数是参数文本文件的路径(必须是绝对路径),第二个参数是列号,从0开始。
3、HTTP请求的Body Data改为:name=${__CSVRead(F:\jmeter\练习\参数\dataLogin.txt,0)}&passwd=${__CSVRead(F:\jmeter\练习\参数\dataLogin.txt,1)}
即可。
__CSVRead()函数和CSV DATA Set Config的区别:
一个是设置的线程组的属性有区别,CSV DATA Set Config要设置循环次数,才会依次去找参数。__CSVRead()设置的是线程数
另外路径,__CSVRead()可以写相对路径,CSV DATA Set Config只能写绝对路径。
__setProperty() 、__property() 属性相关函数:
__setProperty() :设置属性
__property():属性获取
前面讲到关联的地方,讲了同一个线程组中,两个HTTP请求有关联的情况,比如第一个请求是请求百度首页,第二个请求是在搜狗首页,搜索第一个请求返回的title。
之前讲的关联的步骤大致是这样的:
1、新建一个线程组,在该线程组新建HTTP请求,请求百度首页,然后在该请求添加一个后置处理器,xpath提取器或者正则表达式提取器,提取出title。赋值给变量myTitle
2、在线程组内再新建一个HTTP请求,请求搜狗首页,参数设置query=${myTitle}
这样运行就可以了,不会报错,但是如果这两个HTTP请求是在不同的线程组内,这样就不行了。会报如下错误:
myTitle参数没有找到。如何改一下就可以了呢。
可以使用__setProperty()和__property()
步骤:
接着上面的步骤,第三步:
3、点击函数助手,找到__setProperty(),第一个参数是属性名称,起个名字,第二个参数是你要把哪个参数设置为全局参数
4、右键“线程组_setProperty”,添加->Sampler->BeanShell Sampler,将上面生成的__setProperty()函数粘贴到这里。
5、点击函数助手,找到__property()函数,填写属性名称,和setProperty()方法中的一致。
6、修改“线程组_setProperty2”中的“HTTP请求_搜狗”,将原来的${myTitle}修改为:${__property(out,,)},运行就不会报错了。
共享数据(全局变量):
用上面的BeanShell的方式可以设置共享数据,运行完以后可以到工作台中去看到,右键工作台->添加->非测试元件->Property Display
运行完毕后,就可以看到这个值了。
虽然可以这样设置全局变量,但是尽量少用,毕竟它是在你整个运行期间一直占用内存的,即使这个线程组不用了,也不会释放。
8.13 Jmeter分布式
多台测试机协助完成测试任务,就称为分布式。
比如我现在需要测试1500个用户的并发,用一台电脑测试,电脑可能会卡死,这时我就可以使用分布式,分到3台电脑上,每台电脑测试500个。
分布式实现思想:控制机分配任务->执行机,执行测试->将结果给控制机->控制机汇总结果。
8.13.1 Jmeter分布式环境搭建
下面说明一下使用一台控制机,两台执行机来测试,如何搭建环境。
首先要有3台电脑,如果没有,可以暂时使用一台电脑模拟3台,模拟方式:
1、将Jmeter的环境复制3份出来(如果是真实的3台电脑就不需要这样)
2、因为需要联网进行数据交互,所以修改一下执行机的端口号(如果是真实的3台电脑也不需要修改端口号了,因为IP地址肯定不一样)
修改方式:找到执行机A->bin目录->jmeter.properties文件,用记事本打开它。往下拉找到“#server_port=1099”,将#去掉,修改端口号为5553(尽量大一些,省得跟其它冲突),执行机B的也同样方式修改。
3、修改控制机的remote_hosts的值,告诉控制机需要控制哪台机器:
remote_hosts=127.0.0.1:5553,127.0.0.1:5554
(如果使用的是真实电脑测试,将电脑的IP放过来就可以)
ps:环境搭建完毕,注意重启。
8.13.2 Jmeter分布式测试
1、在控制机下编写脚本
这里我们就拿前面的关联那个章节的脚本用吧,将线程数设置为20,添加聚合报告
2、启动所有的执行机,执行机可以不需要界面,只启动Jmeter服务即可(bin目录下的jmeter-server.bat文件)
3、将测试任务分配给执行机(运行->远程全部启动)
测试结果在我们的控制机上就有了,点开聚合报告可以看到请求数刚好40,两台机器,每台20.
8.14 Jmeter控制器
逻辑控制器:
实现取样器的实现顺序(分支或者循环,类似if或者for)
8.14.1 if控制器
比如测试计划有三个请求,分别请求百度,京东,淘宝。定义一个变量,如果变量的值为百度,就请求百度,如果值为京东就访问京东
操作步骤:
1、新建测试计划,右键添加察看结果树,添加用户自定义变量(变量名为name,变量值为百度)
2、右键测试计划->添加->Threads->线程组。
3、右键线程组->添加->逻辑控制器->如果(if)控制器,在条件一栏输入:"${name}" == "百度"
4、右键点击“如果(if)控制器”->添加->sampler->HTTP请求,输入请求百度的信息。
5、运行,查看结果(会访问百度首页),修改自定义变量的名字,再次运行,查看结果(不会访问百度首页)
配置如图:
8.14.2 循环控制器
比如要把百度请求循环5次:
步骤:
1、新建线程组->右键->添加->逻辑控制器->循环控制器
2、修改循环控制器的次数为5
3、右键循环控制器->添加->sampler->HTTP请求,填入百度信息。运行即可
线程组也可以直接设置循环次数,但是线程组设置的话,该线程组内所有的HTTP请求都会循环,循环控制器就比较灵活,可以单独控制某一个请求。
8.14.3 forEach控制器
需求:在百度搜索中依次搜索”hello”,”python”,”测试”
可以用参数化,也可以用forEach控制器
步骤:
1、测试计划右键->添加->配置元件->用户自定义变量
这里要注意变量名必须是一个变量名加下划线的方式,forEach控制器会用到。
2、新建线程组,右键线程组->添加->逻辑控制器->ForEach控制器
变量前缀输入自定义变量中的前缀,循环的开始结束范围,我们有三个变量,所以写[0,3),输出变量名称随便写,下面的勾选是默认的。
3、然后添加一个请求,请求百度首页,上一步的输出变量名称,放到get方法的参数中。
8.15 Jmeter组件QPS
QPS:Query Per Second:吞吐量,每秒查询率,每秒访问服务器资源多少次。
10QPS=每秒访问10次。
需求:一个用户以10QPS的频率访问服务器,持续5s,查看服务器的平均响应时间。(一个用户以每秒10次访问服务器,持续访问5s,查看响应时间)
操作步骤:
1、新建测试计划,添加聚合报告,添加线程组,需求是一个用户每秒访问10次,访问5秒,那么总共就是访问了50次,所以线程组的循环次数设置为50.
2、线程组添加HTTP请求,任意一个请求都可以。
3、右键HTTP请求->添加->定时器->Constant Throughput Timer。填写Target throughput(in samples per minute),这个是填写目标吞吐量,需求是10 QPS,单位是秒,这里需要换算成每分钟多少次,每秒10次也就是每分钟600次。
Calculate Throughput base on:默认选中仅用在本线程组即可。
4、运行之后,查看聚合报告,聚合报告如下:
聚合报告各项意思:
Label:请求的名称,就是我们在进行测试的http request sampler的名称
Samples:总共发给服务器的请求数量,线程组中有一个用户,循环50次,总共就50个请求
Average:默认情况下是单个 Request 的平均响应时间,当使用了 Transaction Controller 时,以Transaction 为单位显示平均响应时间 ,单位是毫秒
Median: 50%用户的请求的响应时间,中位数
90%Line:90%的请求的响应时间
95%Line:95%的请求的响应时间
99%Line:99%的请求的响应时间
Min:最小的响应时间
Max:最大的响应时间
Error%:错误率=错误的请求的数量/请求的总数
Throughput: 默认情况下表示每秒完成的请求数(Request per Second),当使用了 Transaction Controller 时,也可以表示类似 LoadRunner 的 Transaction per Second 数 (这个就是QPS,我们设置的虽然是10,但是这里显示9.1,这样也没关系的,会有一点上下浮动)
Received KB/sec: 每秒从服务器端接收到的数据量
Send KB/sec:每秒发送的请求数
8.16 Jmeter其他组件
Test Fragment:可以封装一些常用请求,当做函数来调用(调用方式可以通过模块控制器调用,也可以通过include Controller)
HTTP mirror server:Jmeter内置服务器(几乎不需要用到)
8.17 Jmeter各组件的执行顺序
1、配置元件:配置一些全局参数
2、前置处理器:运行前需要处理的数据
3、定时器
4、取样器(sampler)
5、后置处理器 :处理响应结果
6、断言
7、监听器
8.18 Jmeter 扩展组件-图形监视器
不是Jmeter官方的,第三方开发的组件,即扩展组件
图形监视器:监视服务器的内存、硬盘、CPU、网络等。模拟生产状态下,服务器状态的测试。
客户端,右键点击线程组->添加->监听器->jp@gc - PerfMon Metrics Collector
然后点击Add Row,可以选择监控CPU、IO、内存等,将前面的IP地址改为服务器IP地址,端口一般默认是4444.
如果监听器中找不到“jp@gc - PerfMon Metrics Collector”,那去下面这个链接下载一下:JMeterPlugins-Standard、JMeterPlugins-Extras,然后解压到这个路径下:...\apache-jmeter-3.1\lib\ext
插件下载链接:https://jmeter-plugins.org/install/Install/
服务器端需要安装ServerAgent,下载后将ServerAgent-2.2.1.jar上传到被测服务器,解压,进入目录。如果是Windows环境,双击ServerAgent.bat启动;linux环境执ServerAgent.sh启动,默认使用4444端口,出现如下情况即服务端成功:
另外,
添加监控响应时间:右键点击线程组->添加->监听器->jp@gc - Response Times Over Time
监听吞吐率即每秒的事务数:右键点击线程组->添加->监听器->jp@gc - Transactions per Second
都添加好之后,点击运行,查看结果即可。
8.19 Jmeter组件:FTP
FTP:文件上传和下载,即将文件上传到服务器或者将服务器资源下载到本地。
首先保证服务器有上传下载文件的功能,即有FTP服务器。
Jmeter中内置了FTP请求,可以通过此请求实现文件传输测试。
操作步骤:
1、右键线程组->添加->Sampler->FTP请求
2、填写服务器名称或IP,IP一般默认为21
3、 Local File:本地的文件路径以及名称;
Remote File:上传后的文件名
Local File Contents:上传的文件的内容,一般不用写
get(RETR):下载文件
put(STOR):上传文件
use Binary mode:使用二进制形式(如果是图片、视频等,就要勾选)
Save File in Response:是否保存文件
4、登录配置:输入FTP服务器的用户名和密码即可。
9 Jmeter项目实战
9.1项目准备
从API文档中提取出接口清单,接口清单包含:URL、提交的数据、响应的数据。
比如测试如下几个接口:
1、开发者注册
请求方式:POST
连接地址:https://api.apiopen.top/developerRegister
参数名 |
类型 |
必需 |
描述 |
示例 |
name |
string |
是 |
用户名 |
peakchao |
passwd |
string |
是 |
密码 |
123456 |
|
string |
否 |
邮箱,用户反馈相关邮件通知。 |
309324904@qq.com |
示例: { "code": 200, "message": "成功!", "result": { "apikey": "b9b3a96f7554e3bead2eccf16506c13e" } }
|
2、开发者登陆
请求方式:POST
链接地址:https://api.apiopen.top/developerLogin
参数名 |
类型 |
必需 |
描述 |
示例 |
name |
string |
是 |
用户名 |
peakchao |
passwd |
string |
是 |
密码 |
123456 |
返回示例: { "code": 200, "message": "成功!", "result": { "apikey": "b9b3a96f7554e3bead2eccf16506c13e" } }
|
3、查看反馈
请求方式:POST
请求链接:https://api.apiopen.top/getFeedback
参数名 |
类型 |
必需 |
描述 |
示例 |
apikey |
string |
是 |
开发者key |
9648872f9aa08da137ce45fe1dda8279 |
page |
string |
否 |
页码 |
1 |
count |
string |
否 |
每页返回数量 |
10 |
返回示例: { "code": 200, "message": "成功!", "result": [ { "id": 2, "text": "我觉得应该再增加个版本更新功能。", "contact": "135@qq.com" } ] } |
9.2功能测试
功能测试就是测试各接口的基本功能是否正常运行,包括发送正确数据和错误数据。模拟用户多样性操作,检测程序响应是否合理。
首先我们需要搭建功能测试框架,其次设计测试用例,再次参数化覆盖测试用例。
1、搭建测试框架
1-1、新建测试计划、添加线程组、添加察看结果树
1-2、添加HTTP请求默认值,服务器名称或IP填写:api.apiopen.top;协议:https;encoding:utf-8
1-3、添加HTTP请求
{"code":200,"message":"成功!","result":{"apikey":"84ed5f753c3243acf59f1fa16ba02dc8","email":null}}
2、设计测试用例
比如注册功能,我们设计测试用例如下图:
3、参数化覆盖
新建一个txt文件,将用例对应的参数写入。线程组右键添加->配置元件->CSV Date,填写参数txt的路径等信息。设置循环次数,运行查看结果即可。
9.3自动化测试
上面讲到的是功能测试,功能测试就需要自己手动去写参数,检查结果。自动化就简单很多,自动化测试尽量遵循以下原则:
- 只测试程序的主要功能以及一些经常被复用的功能,并不是所有用例都自动化。(自动化一般是在功能测试之后测试,比如后期升级了一些新功能,原来的功能不需要都测试,执行自动化测试即可)
- 自动化测试只考虑正向数据(逆向数据太多并且各种组合复杂,程序自动生成有些困难,在功能测试中测试到即可)
- 自动化测试完毕,数据库必须恢复到测试之前的状态(否则会出现问题,比如注册过的用户,再次跑自动化脚本,就不能再注册了)
- 线程组之间尽量不要有关联(即某个请求的输入需要另外一个请求的输出),这样可以单独测试某一个功能。
操作步骤:
1、搭建框架:添加查看结果树、http请求默认值、添加setup线程组和teardown线程组。setup中添加http请求,请求注册。tearDown中删除注册的数据。
2、HTTP请求中的bodyData中写入键值对,值通过__counter函数生成。
bodyData的最终结果:
name=name_${__counter(FALSE,)}&passwd=pwd_${__counter(FALSE,)}&email=67609${__counter(FALSE,)}@qq.com
3、在HTTP请求中添加断言,断言内容就写apikey即可。
4、tearDown中添加删除。删除一般是通过id或者name来删除,这里我们需要获取到HTTP请求中的name,或者结果的apikey,根据这些来删除内容。
添加后置处理器,正则表达式处理器,将结果的apikey获取到:
通过__setProperty方法将myApiKey设置为全局变量:
添加BeanShell Sampler,执行__setProperty方法。
在tearDown中,删除刚刚新增的用户,这个API文档没有删除的功能,所以大概说一下应该如何删。在tearDown中新增一个HTTP请求,使用函数助手,找到__property方法,将全局变量获取到。
在将新增的请求修改bodyData参数:
apikey=${__property(out,,)}
接下来可以添加普通线程组,测试登录、查询等功能。
如果需要依次测试线程组,记得勾选“独立运行每个线程组”。
9.4性能压力测试
模拟多种场景测试程序的响应时间、出错率等
参数化:尽量避免从外部读取参数(测试性能,尽量避免影响性能测试结果的事件),直接通过固定参数+函数形式(__counter())
察看结果树:只保留最外层的察看结果树
报告:最外层添加聚合报告,察看结果更方便
线程组:增删改查分别放到不同线程组,尽量不放到一个线程组内,方便对单个请求做测试
分布式:如并发量比较大,采用分布式测试
新增/删除:新增和删除接口,建议不要采用时间模式(定时器)来压测,直接使用线程数和循环。(新增和删除高并发情况比较少)
需求1:在300秒内启动100个用户,每个用户访问10次服务器,平均响应时间在10ms内,错误率为0.
300秒内,是设置线程组的线程属性Ramp-Up Period值;100个用户表示:线程数为100;每个用户访问10次:循环次数10;
需求2:100个用户同时访问服务器,平均响应时间为10s内,错误率0.
100个用户同时:线程数为100,然后设置集合点:添加->定时器->Synchronizing Timer,分组数为100
需求3:100个用户,以20QPS的频率访问服务器资源,持续10s,要求平均响应时间为30s内,错误率0.
100个用户:线程数为100;20QPS:表示一个用户20次/秒去访问服务器(添加->定时器->Constant Throughput Timer);持续10s,那么循环次数应该为20*10=200
10 生成html测试报告
Jmeter生成html测试报告有两种格式:
格式1:DOS命令行下执行测试脚本,生成HTML测试报告
cmd进入到你的需要测试的脚本路径下,输入一下命令:
Jmeter -n -t 测试计划_实战.jmx -l test.txt -e -o ./outHtml
-n:无图形界面执行Jmeter
-t:后面跟的脚本文件
测试计划_实战.jmx:是需要测试的脚本文件名
-l:后跟日志文件,日志文件后缀只能是.txt或者.jtl或者无后缀。
-o:输出到哪里
./outHtml:输出html到当前路径下的outHtml文件夹中。
格式2:先使用Jmeter运行测试脚本,生成日志文件,再将日志文件转为html格式测试报告。
步骤1.在聚合报告中,有一个“所有数据写入一个文件”,点击浏览,输入一个文件名(输入文件名,点确定后会报错,不用管),运行脚本。
步骤2.进入到日志.txt这个目录,打开cmd,输入命令:
Jmeter -g 日志.txt -o ./报告
-g:关联日志文件
-o:输出