四、JMeter

一、接口测试基础

1.1 接口是什么

1. 接口是系统向外部暴露的交互方式,
2. 接口可以接受来自用户的数据,返回来自系统内部的数据
3. 负责数据的校验、加工、存储、权限控制
4. 是系统内、外的分界线

例子:
  电脑(系统)上面的各种插口(接口)
  电路板上的金属焊点(接口)
  12306上各种订票方式(接口)

1.2 为什么要测试接口

1. 接口测试通过,能保证前端、app、各样功能顺利对接(必要的流程)
2. 接口出现BUG, 会比前端BUG更加严重、影响范围更大(减低风险)
3. 接口测试效率会比UI测试效率高,便于测试,收益更大(提升效率)

1.3 接口怎么测试

1. 模拟软件(需要工具)
2. 对接口进行数据收发(需要专业的工具)
3. 对结果进行判断(支持灵活的断言)

1.4 接口测试工具

1. JMeter: 开元软件,支持多种接口类型、支持接口测试和性能测试,开元进行二次扩展
2. Postman: 收费软件, 简单、方便,适合开发临时调试接口, 需要联网使用
3. APIFOX 等新兴工具: 市场占比比较小,不是主流,适合小团队尝鲜

 

二、JMeter基础

2.1 JMeter 安装配置

2.1.1 jdk安装并配置环境变量

下载地址: https://www.oracle.com/java/technologies/downloads/#java17
配置方式: https://www.cnblogs.com/wangyong123/articles/17844518.html#_lab2_2_1

2.1.2 JMeter安装与配置环境变

下载地址: https://jmeter.apache.org/download_jmeter.cgi

安装结束,记住安装;路径, 双击运行
(Windows)apache-jmeter-5.6.3\bin\jmeter.bat
(Linux)apache-jmeter-5.6.3\bin\jmeter

出现如下界面 则 安装成功

 

添加jmeter启动命令: 环境变量的方式 D:\software\apache-jmeter-5.6.3\bin 加入到 path

通过 cmd的jmeter命令就可以启动jmeter了

 

2.2 核心目录详解

 

目录:
  bin:二进制,存放执行的文件、命令以及配置文件
  docs:文档,内部的API文档
  extras: 额外的,和其他工具进行对接
  lib: 库
    lib/: java的依赖
    lib/ext:JMeter依赖、插件
  printable_docs: 可打印文档,使用说明

核心文件:
  bin/jmeter: 启动文件
  bin/jmeter.properties: 配置文件
  lib: 第三方库

三、JMeter系统结构

3.1 元件类型

3.1.1 核心元件

测试计划: 容器
线程组: 干活的人
取样器: 要干的活

3.1.2 辅助元件

1. 逻辑控制器: 对取样器进行逻辑控制、判断、循环
2. 定时器: 让取样器、延迟一段时间后再执行
3. 监听器: 记录和展示取样器的执行结果
4. 断言: 判断取样器的执行结果
5. 配置元件: 配置、修改取样器的内容
6. 前置处理器: 取样器执行之前,自动执行
7. 后置处理器: 取样器执行之后,自动执行

3.2 元件类型操作练习(请求百度)

3.2.1 请求操作

1. 添加线程组->取样器-> HTTP请求
2. 输入访问百度的协议、服务器名称或者IP、端口号
3. 运行元件

3.3.2 了解请求结果

1. 线程组->监听器->查看结果树
2. 运行元件
3. 查看结果

 

3.3.3 请求三次百度

1. 线程组->逻辑监听器->循环控制器
2. 将HTTP请求和查看结果树移动到循环控制器里面(代表里面循环三次)
3. 输入循环次数为 3
4. 清空原本的结构树内容,重新运行,发现请求次数变为 3

 

 

3.3.3 每次请求之前, 打印: HTTP请求访问百度

1. 循环控制器添加 -> 前置处理器 -> Be按Shell...
2. 输入内容 log.info("HTTP请求访问百度"); java语言,需要符合java规范
3. 运行发现出现三次打印 HTTP请求访问百度

 

3.3 元件加载

1. 加载配置文件
2. 加载线程组
3. 加载取样器
4. 为取样器加载各种复杂元件(比如循环控制器)
  1. 先父级元件
  2. 其次同级元件
  3. 再后子级元件
  4. 不加载旁系元件

修改项目工程目录如下:
其中父级元件、同级元件、子级元件为 后置处理器,中间加入打印信息 log.info("..."),...为当前元件名称

加载顺序是:
  加载线程组 ->
    加载取样器: -- HTTP请求A
    加载元件 :    -- 父级元件
                   -- 同级元件
              -- HTTP请求A子级元件
    加载取样器: -- HTTP请求B
    加载元件 :    -- 父级元件
                   -- 同级元件

 

执行结果如下:

四、JMeter 接口测试简单实战


接口协议:
  http: 默认端口号 80,明文传输,没有安全可研, 在开发、测试环境中使用
  https 默认端口号 443,加密传输,证书校验,防止中间人中宫攻击,生产环境标配

接口关联:
  上一个接口的响应内容,作为下一个接口的请求参数: 通常可以使用变量的方式实现数据传输
  1. 从响应中提取数据到变量
    1)边界值: 适合简单的数据,每次只能提取一个
    2)正则: 适合所有的数据,强大但复杂(用的多)
    3)JSONPATH: 适合JSON数据(用的多)
    4)XPATH: 适合XML数据
    5)CSS: 适合网页数据
  2. 从变量中提取数据到请求
    ${val_name}

参数格式:
  1. 表单: 发送键值对数据: application/x-www-form-urlencoded
  2. JSON: 发送JSON数据(支持多层嵌套,支持多种数据类型)application/json
  3. 文件上传: 上传文件 multipart/form-data;key=......

通过请求头来声明参数格式

4.1 获取微信公众号鉴权码access token接囗

请求URL: https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=appid&secret=secret

请求方式: GET

参数说明:

参数名必选类型说明备注
grant_type string 用户类型 填写: client_credential
appid string 第三方用户唯一凭证 wxc000c173bbf436ba
secret string 第三方用户唯一密钥 d64530af286c88f67eef268bda2642aa

返回示例:
  {"access_token": "ACCESS_TOKEN", "expires_in": 7200}

返回参数说明:

参数名类型说明
access_token string 获取到的鉴权码凭证
expires_in int 凭证有效时间,单位:秒

错误码:

错误码错误码说明
-1 系统繁忙,此时请开发者稍候再试
40001 AppSecret错误或者AppSecret不属于这个公众号请开发者确认AppSecret的正确性
40002 请确保grant type字段值为client credential
40164 调用接口的IP地址不在白名单中请在接口IP白名单中进行设置。
89503 此IP调用需要管理员确认,请联系管理员
89501 此PP正在等待管理员确认,请联系管理员
89506 24小时内该IP被管理员拒绝调用两次,24小时内不可再使用该IP调用
89507 1小时内该IP被管理员拒绝调用一次1小时内不可再使用该IP调用

 

 

使用JMeter测试结果如下: 测试成功

返回结果为:
{"access_token":"82_nzMnHB-l233tJ1iz2xHWxXKuGAP9m9F3KMJ5Q2cKFdfb3xqC7TLpwPwpAoj0xbKXkmHmyZgrq4wpmLD_BNnA1kQ70l-h1pZMfzASw92ZYu01NHNTwgExdI6wsY0AUIeAEAICQ","expires_in":7200}

4.2 获取微信公众号已创建的标签接口

请求URL: https://api.weixin.qq.com/cgi-bin/tags/get?access_token=access_token

说明: access_token 为上一个用例获取鉴权码的返回值的 access_token

请求方式: GET

返回示例:
{
  "tags":[{
  "id":1,
  "name":"每天一罐可乐星人"
  "count":0 //此标签下粉丝数
}
{
  "id":2,
  "name":"星标组”
  "count":0
}
{
  "id":127,
  "name":"广东”
  "count":5
}
]}

4.2.1 直接复制上一个接口的返回值替换到access_token中

 

 

 

使用JMeter测试结果如下: 测试成功

返回结果为:

{"tags":[{"id":2,"name":"星标组","count":0},{"id":1030,"name":"abcd12312312","count":0},{"id":1067,"name":"name","count":0},{"id":1068,"name":"app01","count":0},{"id":1072,"name":"app001","count":0},{"id":1079,"name":"\\u5e7f\\u897f4","count":0},{"id":1089,"name":"wuhan008","count":0},{"id":1090,"name":"wuhan007","count":0},{"id":1092,"name":"wuhan005","count":0},{"id":1093,"name":"wuhan004","count":0},{"id":1101,"name":"\\u6df1\\u5733","count":0},{"id":1102,"name":"\\u65e0\\u7f18","count":0},{"id":1138,"name":"\\u6df1\\u57331","count":0},{"id":1149,"name":"\\u5e7f\\u4e1c","count":0},{"id":1150,"name":"\\u5e7f\\u4e1c2","count":0},{"id":1151,"name":"\\u5e7f\\u4e1c2311141","count":0},{"id":1152,"name":"\\u5e7f\\u4e1c2311132","count":0},{"id":1153,"name":"\\u5e7f\\u4e1c2311192","count":0},{"id":1154,"name":"\\u5e7f\\u4e1c23111580","count":0},{"id":1155,"name":"\\u5e7f\\u4e1c23111260","count":0},{"id":1156,"name":"\\u5e7f\\u4e1c2311150","count":0},{"id":1164,"name":"jiangxi5262","count":0},{"id":1165,"name":"jiangxi61439","count":0},{"id":1166,"name":"jiangxi96958","count":0},{"id":1181,"name":"\\u5e7f\\u4e1c2311144","count":0},{"id":1182,"name":"\\u5e7f\\u4e1c2311145","count":0},{"id":1202,"name":"002","count":0},{"id":1203,"name":"003","count":0},{"id":1204,"name":"\\u5e7f\\u4e1c23111270","count":0},{"id":1205,"name":"004","count":0},{"id":1206,"name":"i001","count":0},{"id":1207,"name":"i002","count":0},{"id":1208,"name":"i003","count":0},{"id":1209,"name":"i004","count":0},{"id":1210,"name":"q001","count":0},{"id":1211,"name":"q002","count":0},{"id":1212,"name":"q003","count":0},{"id":1213,"name":"q0040","count":0},{"id":1214,"name":"s001","count":0},{"id":1215,"name":"s002","count":0},{"id":1216,"name":"s003","count":0},{"id":1217,"name":"s0040","count":0},{"id":1218,"name":"s004","count":0},{"id":1219,"name":"w001","count":0},{"id":1220,"name":"w002","count":0},{"id":1221,"name":"w003","count":0},{"id":1222,"name":"w0040","count":0},{"id":1225,"name":"fNFoirqKsT","count":0},{"id":1226,"name":"Rd8034G5zy","count":0},{"id":1227,"name":"D6rnxQcLTM","count":0},{"id":1228,"name":"jetGZwNxiT","count":0},{"id":1229,"name":"YkA9T8lvxQ","count":0},{"id":1230,"name":"DxYHPA4f0e","count":0},{"id":1231,"name":"xDCpEQsQ2E","count":0},{"id":1232,"name":"ImXYUmUtLv","count":0},{"id":1233,"name":"{{edit_tag_name}}","count":0},{"id":1248,"name":"${time_join_str(\\u56db\\u5ddd)}","count":0}]}

4.2.2 使用后置处理器的JSON处理器处理

后置处理器的JSON处理器 完成 从响应中提取数据到变量

$ 代表根路径
. 代表字段

 添加调试取样器,这样就可以看到所有调试的返回值,也就是将第一个接口的响应内容提取到这里

 

修改请求的路径如下:

重新运行,测试成功

 

4.3 获取微信公众号编辑标签接口

请求URL: https://api.weixin.qq.com/cgi-bin/tags/update?access_token=ACCESS_TOKEN

请求方式: POST

请求参数: {"tag":{"id":134,"name":"王勇"}}

返回示例: {"errcode":0,"errmsg":"ok"}

返回参数说明:

参数名类型类型
errcode int 错误码,0表示成功
errmsg string 错误信息,ok表示成功

 运行,发现请求参数的 Content-Type 是不正确的,但是结果是对的,其实是微信公众号提供的一些处理功能,实际上不可以的

 

因为请求头不正确,所以我们添加请求头方式

重新运行,测试成功

使用JMeter测试结果如下: 测试成功

返回结果为:

  {"errcode":0,"errmsg":"ok"}

 

 

 

五、JMeter断言

5.1 默认断言

默认情况下,会检查 HTTP 的状态码, 如果状态码 < 400, 视为成功

100: 继续请求
200: 请求成功
300: 重定向(重新发送请求)
400: 客户端错误(请求的不对)
500: 服务端错误(内部 BUG)

问题: 现在很多接口会把错误信息放在接口数据中,状态码一律是 200

5.2 断言元件

5.2.1 响应断言

把响应看成字符串,然后检查有没有制定的字符串出现。 如果判断条件为出现 fail 那么用例判定失败。即使是在返回数据 result,存在 if(result == fail) .. else  的选择处理程序,那么也会判定失败

5.2.2 JSOn断言

从 JSON 中提取数据, 对提取出来的数据进行匹配

5.3 自定义断言

根据业务需求,自定义测试通过或者失败的标准

1. 如果同时出现 success 和 fail, 断言通过
2. 如果只出现 fail,断言失败

sampler_code = prev.getResponseCode() //实际取样代码
sampler_data = prev.getResponseDataAsString() // 实际取样内容

//正则统计关键字出现次数
coun_fail = (sampler_code =~ /fail/ ).size()
coun_success = (sampler_data =~ /success/ ).size()
log.info("fail: ${coun_fail} success: ${coun_success}")

// 判断关键字出现的
if (coun_success==0 && coun_fail >0){
    log.info('断言失败')
    AssertionResult.setFailure(true)
    prev.setSuccessful(false) //修改取样器结果
    AssertionResult.setFailureMessage("有fail出现 ")
}else{
    log.info('断言成功')
    AssertionResult.setFailure(false)
    prev.setSuccessful(true) //修改取样器结果
}
log.info("自定义断言完成")

六、基于项目整体分析的实战

6.1 项目接口文档

https://www.cnblogs.com/wangyong123/articles/18350271

6.2 项目分析

1.项目使用了Cookies
2.接口返回值有HTML也有JSON
3.失败的标志:fail为失败
4.多出接口关联
5.服务器信息:http://47.107.116.139/
6.需要用到辅助函数:随机数,时间戳,自增ID,UUID

1.项目使用了Cookies
2.接口返回值有HTML也有JSON
3.失败的标志:fail为失败
4.多出接口关联
5.服务器信息:http://47.107.116.139/
6.需要用到辅助函数:随机数,时间戳,自增ID,UUID

6.3 创建公共元件

1. Cookies管理器
2. 断言: 没有失败
3. 用户变量
4. HTTP默认值
5. 创建公共查看结果树
6. 修改配置D:\software\apache-jmeter-5.6.3\bin\jmeter.properties
  CookieManager.save.cookies =true // 将cookie自动保存为变量

 

 

断言

  1. 无fail(后面自定义断言,被禁用)
  2. 相应断言(不存在错误提示断言成功)
  3. 自定义断言

 

 

 http默认请求头:

 辅助函数(创建不可重复的值,UUID):

6.4 补全取样器的请求元件

6.4.1 访问phpwind论坛首页接口

6.4.2 登录接口

6.4.3 登录成功后跳转接口

6.4.4 点击[板块]进入列表接口

6.4.5 点击[新板块]进入板块接口

6.4.6 点击【发帖】进入发帖接口

6.4.7 发帖接口

6.4.8 跳转到帖子内容页接口

七、接口加密解密

7.1 接口加密基础

在普通接口的基础上,对参数(数据)进行动态修改,从而隐藏原始内容原理:根据对应加密算法,对于内容进行变换,实现隐藏、无法伪造目的

算法:
  不需要还原:哈希算法
    速度快,但是无法还原
    用于:签名、文件校验常用算法:
    MD5
    SHA
  需要还原:加密算法
    速度慢,但是可以还原
    对称加密:加密、解密过程对称: AES
    非对称加密:加密、解密过程不对称:RSA

7.2 接口加密文档

https://www.cnblogs.com/wangyong123/articles/18350361

7.3 接口加密实战

7.3.1 企业MD5加密接口

// MD5 加密代码

import org.apache.commons.codec.digest.DigestUtils;
username_md5 = DigestUtils.md5Hex("admin");
password_md5= DigestUtils.md5Hex("123");
vars.put("username_mds",username_md5);
vars.put("password_mds",password_md5);

 

7.3.2 企业BASE64加密接口(方法和上面一样)

// base64 加密代码
import java.util.Base64;

encoder = Base64.getEncoder();
username_b64 = encoder.encodeToString("admin".getBytes("UTF-8"));
password_b64 = encoder.encodeToString("123".getBytes("UTF-8"));
vars.put("username_b64",username_b64);
vars.put("password_b64",password_b64);

八、DDT 数据驱动测试

数据决定了用例的数量和用例的内容

测试上面的MD5加密的用例, 测试结果符合用例给的参数,测试成功

DDT.csv配置文件内容如下:

username_md5,password_md5,error_code
21232f297a57a5a743894a0e4a801fc3,202cb962ac59075b964b07152d234b70,0
,202cb962ac59075b964b07152d234b70,101
21232f297a57a5a743894a0e4a801fc3,,101
,,101

 

 

 

 

posted on 2024-08-08 16:17  软饭攻城狮  阅读(6)  评论(0编辑  收藏  举报

导航