Jmeter做接口测试

一.Jmeter的安装以及环境变量的配置

Jmeter是基于java语法开发的接口测试以及性能测试的工具。
jdk:17 (最新的Jeknins,只能支持到17)
jmeter:5.6 官网:http://jmeter.apache.org/download_jmeter.cgi
认识JMeter的目录:
backups目录:备份脚本
bin目录:模板,主jar包,启动文件,jmeter.propties全局配置文件。jmeter-server.bat分布式压
测。
修改全局配置文件:
language=zh_CN 设置为中文
sampleresult.default.encoding=utf-8
extras目录:存放和集成第三方的一些文件。
lib目录:jar包

二.Jmeter进行常规的接口测试

1.测试计划

在一个测试计划中可能存在多个线程组

线程组之间在执行时是没有顺序的。如果希望线程按顺序执行,则需要勾上【独立运行每个线程组】

2.Jmeter的组件作用域

组件可以作用于父组件
组件可以作用于同级组件
组件可以作用于同级组件的子组件

3.线程组和测试片段

测试片段就是一个特殊的线程组

线程组

线程组适用于自己调试或者单个测试人员去调试

在线程组中也可以创建模块控制器去执行测试片段

测试片段和include处理器

测试片段是特殊的线程组,和线程组同级别。用于多个测试之间协同做接口测试。主要是和模块控
制以及Include控制结合使用。

特点:
1.默认是禁用状态。
2.单个测试片段无法执行,需要结合模块控制器(自己调试)以及Include控制器(leader)执行。

使用include控制器去执行该测试片段(注意:要添加对应的测试片段存放路径)

4.测试单个接口

接口信息(事例)

添加配置原件

HTTP请求默认值

协议: 根据url

服务器名称或IP: 跟在协议后面的第一段字符串

端口号: http--80,https--443

HTTP Cookie管理器

用于传入cookie

用户定义的变量

相当于全局变量

填写接口信息

新建一个http请求,然后填入相关信息

web服务器: 同HTTP请求默认值, 如果信息与默认值相同则不用填, 如果不同则填

HTTP请求: GET,POST,PUT....(根据接口信息填)

路径: 接口的url

如果请求默认值中的协议和IP与其对应, 可以只填写IP地址后面的字符串,如下:

查看接口执行结果

添加一个查看结果树

执行后进去查看对应接口的执行结果,查看响应信息是否符合期望

5.接口关联(多个接口)

什么是接口关联

当一个接口(接口1)的响应结果为另一个接口(接口2)的传参时, 需要先执行接口1,并通过提取器获取对应的结果数据, 然后将结果数据再放入接口2的对应位置

常用提取器

正则表达式提取器

引用名称相当于变量名, 可使用 ${引用名称} 来使用该变量

正则表达式可以提前在查看结果树中测试是否可以获取得到

语法: 使用字典的形式填写,在value部分填入 (.*?) 即可(记得加引号)

如果要获取多个值,可以在木板部分加入多个 $*$ 的结构 一个 $*$ 代表接收一个对应位置的值

边界提取器

语法: 和正则比较相似

左边界为:  "key":"

右边界为:  "

JSONpath提取器

Json语法:
(1) $ 根节点
(2).或[] 去子节点
(3)如果是数组(llist),则通过下标取值
(4)相对路径用法:$..name 这里的name一般需要唯一。
(5)列表切片:$.tags[0:3]
总结:看到字典则用. 看到列表则用[0]下标,下标从0开始。

Xpath提取器

同web自动化里面的定位方式,一般用于返回html网页时。

关联事例

在上一个接口中我使用正则表达式提取机中的引用名称为token,所以该接口的路径如下填写:

6.动态参数接口测试

工具--》函数助手对话框。
1.随机数字函数(在给定数字范围随机一个整数)

2.随机字符串函数(根据传入的内容字符串和长度,随机出一个新的字符串)


3.随机时间戳函数(根据当前时间生成时间戳)


4.其他函数(如字符串大写)(使用JavaScript函数)

在字符串(带变量的字符串也可以)后面加上 .toUppCase() 

三.接口测试常规断言和数据库断言

常规断言

断言作用在接口用例中

1.响应断言

2.json断言

3.beanshell断言

主要通过Failure标识是否失败和FailureMessage标识失败信息。
Failure=true 失败,Failure=false 成功。

数据库断言(TO DO)

四.反例接口测试(使用CSV)

首先在要添加反例的接口用例下面加上一个 CSV 数据文件设置 和 一个响应断言

如果有需要执行多次接口的情况(该接口有多个反例和正例需要执行)

可以将该接口放到循环控制器下面,并在循环控制器中设置执行的次数(次数根据要执行的用例数量而定)

然后创建一个.csv文件

第一行写接口的参数

最后加上一个断言的参数

然后就可以添加正例和反例的传参

最后的断言字符串可以通过运行用例查看报错信息获取到,如下:

五.跨线程组实现接口关联

使用场景

有接口1和接口2, 接口1的响应数据是接口2的传参, 假如现在要对接口2进行压测, 因为接口2需要接口1的数据, 所以需要接口1和接口2同时运行, 此时压测的就是两个接口, 如果我们只想对接口2进行压测, 那么就需要使用跨线程组实现接口关联

实现(接口场景如上)

步骤1: 首先对接口1中的响应数据使用提取器进行提取(提取器的使用前面有说)

步骤2: 在接口1中新增一个 BeanShell后置处理程序(将变量转换为全局变量) ,使用函数助手的setProperty函数 生成全局变量的字符串,并将字符串粘贴到脚本处

 步骤3: 在接口2中使用该全局变量

(1)打开函数助手, 使用property函数, 将全局变量进行转换

(2)将复制的变量名放到接口2对应的参数位置

六.Cookie关联

场景(适用于下面两个事例)

场景: 接口1的响应头中可以获取到cookie, 接口2需要传入cookie进行登录

同线程组的Cookie关联

结构:

使用提取器对接口1的响应头进行提取,注意要选中 信息头 

提取后再接口2中的对应位置进行传参

最后新增一个HTTP Cookie管理器,就完成了.

跨线程组的Cookie关联

步骤1: 首先对两个接口进行跨线程组关联的测试(此处就不演示了)

步骤2: 获取cookie

(1)修改配置文件全局配置文件 jmeter.propties 中 CookieManager.save.cookies=true

注意: 修改完要进行重启, 如果使用cmd打开, 则cmd也需要重启

(2)在接口1的响应头和接口1的调试取样器中找到cookie(注意在全局要加上HTTP Cookie管理器在执行)

接口1和调试取样器里面cookie的名字要保持一致(接口1header中set-cookie的 cookie 名=调试取样器body中的 cookie 名减去前面的COOKIE_)

步骤3: 

(1)在接口1中新增一个 BeanShell 后置处理程序 

(2)使用 setProperty函数 对 接口1 -> header -> set-cookie字段 -> cookie名 生成字符串,填入脚本的位置

接口1 -> header -> set-cookie字段 -> cookie名 如下:

步骤4: 在HTTP Cookie管理器添加Cookie

(1)此处的名称为接口1 -> header -> set-cookie字段 -> cookie名. 如下:

(2)使用property函数将对应的cookie名生成字符串,放入值的位置.

(3)域 为 域名(要访问网站的IP地址)

步骤5: 在接口2的参数位置填入对应的cookie变量

七.BeanShell组件的使用

BeanShell组件自带的语法

BeanShell支持 java的语法 也有 自带的语法

BeanShell共有六种:

(1) BeanShell断言 -- 调用时机: 请求后

(2) BeanShell前置处理器 -- 调用时机: 请求前

(3) BeanShell取样器 -- 调用时机: 请求

(4) BeanShell后置处理器 -- 调用时机: 请求后

(5) BeanShell定时器 -- 调用时机: 请求前

(6) BeanShell监听器 -- 调用时机: 请求后

1. log -- 打印

2. vars -- 操作jmeter的局部变量(线程组内的变量)

(1)vars.get(key);

返回一个局部变量,在当前线程组下可使用.

(2)vars.put(key,value);

设置一个局部变量,在当前线程组下可使用.

对于【用户定义的变量】可以直接通过vars.get()取值
对于通过【正则表达式】或其他表达式获取到的中间变量可以直接通过vars.get()取值
不同的beanshell之间可以相互设置或者获取值。

3. props -- 操作jmeter的全局变量

(1) props.put(key,value);

设置一个全局变量

(2) props.get(key);

获取一个全局变量(局部变量获取不到)

举例:(在测试计划中将 [独立运行每个线程组] 勾选)

在线程组1中设置一个全局变量

在线程组2中设置一个局部变量

在线程组2中获取全局变量和局部变量并进行打印

4. prev -- 获取响应的信息

(1) prev.getResponseCode()

获取响应码

(2) prev.getResponseDataAsString()

获取响应数据, 并作为字符串返回

举例:

在接口中新建一个BeanShell 后置处理程序, 调用两个方法并打印结果.

BeanShell组件调用Java程序

通过source()引入Java文件

(1)首先创建一个Java项目,写好一个类并写好目标方法,找到项目文件中目标方法的所在类的路径(.java文件) 此处不演示了.

(2)在BeanShell组件中使用source()引入路径,即可使用

在测试计划中导入jar包

(1) 和source()的第一步一样, 多了一步打成jar包,然后在测试计划中导入jar包

(2) 在BeanShell组件中导入目标方法的包,然后使用

BeanShell组件调用Python程序

注意: 如果调用的py文件是复制到某一路径再去调用的, 重新编辑py文件后要进行覆盖才能运行到新的python代码

调用无参数的函数

1. 创建python项目,写好函数

2. 在BeanShell组件中写如下代码(大部分都是固定的,更改部分通常只有文件路径)

其本质是在cmd中执行.py文件,然后再获取它的打印值

代码如下: 

python代码:

import time


def get_random_number():
    times = str(int(time.time()))
    print(times)

if __name__ == '__main__':
    get_random_number()

BeanShell代码:

import java.io.BufferedReader;
import java.io.InputStreamReader;

//创建cmd命令 并执行py文件
String command = "cmd /c python D:\\JmeterTest\\test.py";//python后面是.py文件的路径
//创建一个运行时对象
Runtime rt = Runtime.getRuntime();
//通过运行时对象运行cmd命令
Process pr = rt.exec(command);
//运行时等待
pr.waitFor();
//调用pr进程对象获取到输入流,读取pr文件流,并保存到reponse_data变量中
InputStreamReader input = new InputStreamReader(pr.getInputStream());
BufferedReader br = new BufferedReader(input);//BufferedReader是缓存读取,读取pr文件流缓存区
StringBuilder response = new StringBuilder();//用来后面保存 "输出字符串"
String line = "";//获取缓存字符串(循环变量)
//循环尝试获取缓存区字符串
while( (line=br.readLine()) != null ) {
	response.append(line);//获取到,保存
}
String response_data = response.toString();//保存到String对象中
br.close();

//打印返回的内容
log.info("response_data: " + response_data);

调用单个参数的函数

python代码

因为有了参数, 所以要去获取cmd命令中的参数(注意,这里不是在函数的形参中增加参数!!)

import argparse
import time


def get_random_number():
    # 获取cmd命令里面的参数
    parse = argparse.ArgumentParser()
    parse.add_argument("-t", "--ticket")
    args = parse.parse_args()
    ticket = args.ticket

    # 获取当前时间戳并打印
    times = str(int(time.time()))
    print(ticket + times)

if __name__ == '__main__':
    get_random_number()

BeanShell代码

和前面调用无参函数相比, 调用有参函数在BeanShell脚本中只需要在.py文件路径后面传参即可.

传参的方式就是"cmd /c .py文件路径 -t 参数"

import java.io.BufferedReader;
import java.io.InputStreamReader;

//创建cmd命令 并执行py文件
String command = "cmd /c python D:\\JmeterTest\\test.py -t abcdefg";//python后面是.py文件的路径 -t后面是参数的内容
//创建一个运行时对象
Runtime rt = Runtime.getRuntime();
//通过运行时对象运行cmd命令
Process pr = rt.exec(command);
//运行时等待
pr.waitFor();
//调用pr进程对象获取到输入流,读取pr文件流,并保存到reponse_data变量中
InputStreamReader input = new InputStreamReader(pr.getInputStream());
BufferedReader br = new BufferedReader(input);//BufferedReader是缓存读取,读取pr文件流缓存区
StringBuilder response = new StringBuilder();//用来后面保存 "输出字符串"
String line = "";//获取缓存字符串(循环变量)
//循环尝试获取缓存区字符串
while( (line=br.readLine()) != null ) {
	response.append(line);//获取到,保存
}
String response_data = response.toString();//保存到String对象中
br.close();

//打印返回的内容
log.info("response_data: " + response_data);

执行结果:

调用多个参数的函数

python脚本要做出一些修改, 因为传入了多个参数,所以需要将这些参数追加为一个list

如下:

import argparse
import time


def get_random_number():
    # 获取cmd命令里面的参数
    parse = argparse.ArgumentParser()
    # action="append"的意思是: 如果有多个参数使用追加的方式
    parse.add_argument("-t", "--ticket", action="append")
    # 如果使用了追加的方式 会将其追加为一个list
    args = parse.parse_args()
    ticket = args.ticket

    # 获取当前时间戳
    times = str(int(time.time()))
    # 打印list
    print("ticket: %s" % ticket)
    # 打印时间戳
    print(times)

if __name__ == '__main__':
    get_random_number()

BeanShell脚本的修改同调用单个参数,加多个 -t 参数 即可

import java.io.BufferedReader;
import java.io.InputStreamReader;

//创建cmd命令 并执行py文件
String command = "cmd /c python D:\\JmeterTest\\test.py -t abcdefg -t hhhhhh";//python后面是.py文件的路径
//创建一个运行时对象
Runtime rt = Runtime.getRuntime();
//通过运行时对象运行cmd命令
Process pr = rt.exec(command);
//运行时等待
pr.waitFor();
//调用pr进程对象获取到输入流,读取pr文件流,并保存到reponse_data变量中
InputStreamReader input = new InputStreamReader(pr.getInputStream());
BufferedReader br = new BufferedReader(input);//BufferedReader是缓存读取,读取pr文件流缓存区
StringBuilder response = new StringBuilder();//用来后面保存 "输出字符串"
String line = "";//获取缓存字符串(循环变量)
//循环尝试获取缓存区字符串
while( (line=br.readLine()) != null ) {
	response.append(line);//获取到,保存
}
String response_data = response.toString();//保存到String对象中
br.close();

//打印返回的内容
log.info("response_data: " + response_data);

执行结果:

传入的参数为变量

方法一: 只需要再传入的cmd字符串中把固定值改成变量即可(注意路径要使用左斜杠"/")

方法二: 通过get将全局变量获取为局部变量,然后进行字符串拼接

八.接口加密

1.对称加密(BASE64)

在接口中新建一个 BeanShell预处理程序 ,添加如下脚本(打印部分可以去掉)

大概内容就是: 先对需要加密的字符串进行加密, 然后再将其设置成变量, 方便传参

import java.util.Base64;

//初始化一个Base64对象,调用encodeToString()方法             加密的字符串   确认编码格式
String username_miwen = Base64.getEncoder().encodeToString("admin".getBytes("UTF-8"));
String password_miwen = Base64.getEncoder().encodeToString("123".getBytes("UTF-8"));
//打印加密后的结果
log.info(username_miwen);
log.info(password_miwen);
//将结果设为变量
vars.put("username_miwen",username_miwen);
vars.put("password_miwen",password_miwen);

变量版本: 

import java.util.Base64;

//创建临时变量接收参数内容(未加密前的参数)
String username = vars.get("usernames");
String password = vars.get("passwords");
//初始化一个Base64对象,调用encodeToString()方法
String username_miwen = Base64.getEncoder().encodeToString(username.getBytes("UTF-8"));
String password_miwen = Base64.getEncoder().encodeToString(password.getBytes("UTF-8"));
//打印加密后的结果
log.info(username_miwen);
log.info(password_miwen);
//将结果设为变量
vars.put("username_miwen",username_miwen);
vars.put("password_miwen",password_miwen);

然后调用变量传参

2.只加密不解密

MD5加密

方法一: 使用函数助手中的digest函数

然后使用复制的变量进行传参即可

方法二: 写BeanShell脚本

在接口下新建一个BeanShell预处理程序, 添加如下脚本

//导包
import org.apache.commons.codec.digest.DigestUtils;
//md5加密
String username_miwen = DigestUtils.md5Hex("admin");
String password_miwen = DigestUtils.md5Hex("123");
//传值
vars.put("username_miwen",username_miwen);
vars.put("password_miwen",password_miwen);

然后调用变量传参

SHA系列加密

SHA系列有多个版本: 使用较多的有224、256、512版本

方法一: 在函数助手中的digest函数可以调用sha-3之外的版本

方法二: 使用BeanShell脚本(不支持sha-3, sha-224)

import org.apache.commons.codec.digest.DigestUtils;
String miwen = DigestUtils.sha512Hex("admin");//sha1Hex,sha256Hex...
log.info("加密结果为:"+miwen);

3.非对称加密

python代码

import argparse
import base64
import rsa
#通过公钥加密
def rsa_jiami():
    # 接收cmd命令里面的参数
    parse = argparse.ArgumentParser()
    parse.add_argument("-t", "--ticket", action="append")
    args = parse.parse_args()
    ticket = args.ticket
    #print("ticket:%s" % ticket)
    #导入公钥
    public_key_str = "-----BEGIN RSA PUBLIC KEY-----\nMIGJAoGBALO7UPE26anTGHND2Q54zYYPusDx+tbO1Yia7zoxpZediw+Baea7aFZC\nJ+ZvWd5ZBTopuWvb8hNkY24eBHcXN0pU32WjsH9REp1kXhxbndnw+u3diaoUFqVc\n66xl+LXEo1Y9oDWfkGCir2JnN0aieUiPlHDLhmc+LII/ZDspITKDAgMBAAE=\n-----END RSA PUBLIC KEY-----"
    pubkey = rsa.PublicKey.load_pkcs1(public_key_str.encode())
    #加密用户名
    username_str = rsa.encrypt(str(ticket[0]).encode("utf-8"), pubkey)
    #把二进制转化成字符串格式
    username_miwen = base64.b64encode(username_str).decode("utf-8")
    print(username_miwen)
    print("分隔符")
    # 加密密码
    password_str = rsa.encrypt(str(ticket[1]).encode("utf-8"), pubkey)
    # 把二进制转化成字符串格式
    password_miwen = base64.b64encode(password_str).decode("utf-8")
    print(password_miwen)
if __name__ == '__main__':
    rsa_jiami()

BeanShell代码

import java.io.BufferedReader;
import java.io.InputStreamReader;

//创建cmd命令 并执行py文件
String command = "cmd /c python D:/JmeterTest/RSA_jiami.py -t ${username} -t ${password}"; //python后面是.py文件的路径
Runtime rt = Runtime.getRuntime();
//初始化一个运行时对象
Process pr = rt.exec(command);
//通过运行时对象运行cmd命令。
//运行时等待
pr.waitFor();
//调用pr进程对象获取到它的输入流。读取pr文件流的内容,并且保存到response_data
BufferedReader br = new BufferedReader(new InputStreamReader(pr.getInputStream()));
StringBuilder response = new StringBuilder();
String line = "";
while((line=br.readLine())!=null){
	response.append(line);
}
String response_data = response.toString();
br.close();
//打印返回的内容
log.info("response_data:"+response_data);
//获取用户名和密码
String[] miwen = response_data.split("分隔符");
log.info(miwen[0]);
log.info(miwen[1]);
vars.put("username_miwen",miwen[0]);
vars.put("password_miwen",miwen[1]);

在接口中传入值

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

追梦不止~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值