使用Metersphere进行自动化测试和压力测试

使用Metersphere进行自动化测试和压力测试
Photo by Arno Senoner / Unsplash

1. 自动化测试

1.1 定义接口

手动创建

image-20220814133619675

批量导入接口

支持从postman、jmeter、swagger导入。需要主机的是,从Jmeter导入的接口不会附带断言、前置处理脚本等内容,只能导入接口本身。

image-20220814133820208

image-20220814133905308

1.2 环境配置

创建环境

环境属于项目的配置,所以需要在项目配置中进行配置。

主要需要配置的内容有:环境通用的变量、域名、数据库、前置后置脚本、全局断言等等

image-20220814134319547

image-20220814134402196

1.3 新建场景

开始分场景进行自动化测试的编写

image-20220814134738526

添加步骤、导入接口

点击右下角的加号 添加“步骤”

选择接口列表导入,导入之前创建的接口

image-20220814135032175

image-20220814140053002

设置接口前置后置处理

image-20220814142136583

选择前置、后置脚本 点击添加

然后将之前在Jmeter写好的Beanshell后置处理器中的脚本粘贴进来

image-20220814142849221

配置场景变量

将之前在Jmeter中的用户自定义变量和http请求头配置写在这里

image-20220814140743793-2

指定运行环境、执行测试

image-20220814143322430

1.4 遇到的问题和解决方式

1.4.1 Metersphere无法通过sampler.getArguments()拿取get请求的入参

因为项目请求需要经过加密,而加密需要在请求前拿取请求参数,进行加密后重新给请求头中sign等字段赋值,所以需要拿取现有请求入参,并转为map以便后续处理,Jmeter Beanshell代码如下:

import org.apache.jmeter.config.Arguments;

//获取请求入参args,转为map
Arguments args = sampler.getArguments();
log.info("请求数据====" + args);
Map argsMap = args.getArgumentsAsMap();
log.info("argsMap    ==============" + argsMap);

但以上代码在MeterSphere中无法拿取到get请求 (MeterSphere版本 v1.20.6-lts)(而且奇怪的是post请求的入参是可以拿取到的)

所以需要手动从url中拿取String格式的参数字段,再自己进行处理,代码如下:

String requestQuery = sampler.getUrl().getQuery();
//此处requestQuery拿取的为get请求url中?后面的内容
log.info("请求数据====" + requestQuery);


//转map
Map argsMap = new HashMap(0);
String[] params = requestQuery.split("&");
for (int i = 0; i < params.length; i++) {
    String[] p = params[i].split("=");
    if (p.length == 2) {
        argsMap.put(p[0], p[1]);
    }
}

1.4.2 前置、后置处理器中的Base64加密脚本在Metersphere中执行失败

使用MeterSphere测试平台进行自动化测试时,发现引入的一个第三方jar中的方法在执行时报错:

java.lang.NoClassDefFoundError: sun/misc/BASE64Encoder

分析之后发现 sun/misc/BASE64Encoder 这个包仅在jdk1.8以及之前的版本存在,更高版本的jdk不存在了。 而MeterSphere(1.20lts)使用的jdk版本是jdk11。

所以需要自己对引用的jar进行改造。

先用idea插件java-decompiler.jar对原有加密包tt.hlhtAes.jar进行反编译

然后自己新建项目,把反编译出的代码放进项目中进行修改:

  1. 添加 commons-codec 依赖
<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.6</version>
</dependency>
  1. 代码中引入
import org.apache.commons.codec.binary.Base64
  1. 替换原来的BASE64Encoder()

    加密部分
    将:

    BASE64Encoder base64encoder = new BASE64Encoder();
    return base64encoder.encode(xxx);
    

    替换为:

    Base64.encodeBase64String(xxx);
    

    解密部分
    将:

    new BASE64Decoder().decodeBuffer(xxx);
    

    替换为:

    Base64.decodeBase64(xxx);
    

然后重新打包即可。

不会打Jar包的点这里: JAVA-如何打包成jar包_@花花.的博客-CSDN博客_打jar包

1.4.3 拼接Bearer xxxxxxxx格式的token

JWT标准中请求头中需要加上authorization参数,该参数是由固定字符串和从上个接口返回的token字段一起拼接而成

所以在接口自动化脚本编写时,要进行字符串的拼接

  1. 打开jmeter上的函数助手,选择—V功能,按下图步骤输入想拼接的字段组合,点击生成:
    ----_20220707160050
  2. 粘贴到使用该函数结果的位置,如无其他参数,要去掉最后面的逗号,最终结果如下:
${__V(Bearer ${token})}

2. 使用Metersphere进行压力测试

2.1 场景配置

可以引用接口自动化场景

也可以直接上传已经写好的jmx文件

2.2 压力配置

image-20220814163150176

这里:

并发用户数=Jmeter中的线程数

RPS开启=Jmeter中启用Throghput Shaping Timer 但可配置的只有上限

2.3 高级配置

可以配置连接超时、响应超时的时间、自定义变量等等

最重要的高级配置是CSVDataSet。 可以通过在场景变量中上传文件的方式来进行数据驱动的压力测试,如下图所示:

img

img

2.4 CSVDataSet与线程组

讨论一下Metersphere中对CSVDataSet支持与Jmeter中的区别。

Jmeter中CSVDataSetConfig是可以设置数据文件的应用范围的,详细的情况在下方引用中。 但在Metersphere中,没有选项可以配置,默认为**”当前线程组“**。 也就是说,整个线程组读取一次文件。然后每个线程(也就是所谓每个用户)依次读取文件,即:第一个线程读取第一行数据,第二个线程读取第二行数据,以此类推。

  • 全部线程

    是指在CSV Data Set Config配置元件作用域范围内的所有线程共享一个数据源文件,也就是说在JMeter测试执行过程中,JMeter仅打开一次该数据源文件,每个线程读取的是同一个数据源文件中的数据.线程按照启动的先后顺序依次从数据源文件中获取一个值,不论该线程是否引用CSV Data Set Config中定义的变量,每个线程都会分配一个值,这样可以保证每个线程获取的是数据源文件中不同行的列值(在不循环取值的情况下).

  • 当前线程组

    是指在CSV Data Set Config配置元件作用域范围内的所有线程组,当JMeter执行测试时,每一个线程组都单独打开一次数据源文件(可以是相同或不同的数据源文件).每个线程组下的各个线程都是从数据源文件的起始处读取参数值.

    若要线程组读取不同的数据源文件,可以对数据源文件的路径进行参数化.
    这里需要使用{threadGroupName}来获取线程组的名字.
    假设有n个线程组:tg1,tg2,…,tgn
    每个线程组对应一个数据源文件,对应的文件名分别为: tg1.csv,tg2.csv,…,tgn.csv
    在配置时将”Filename”设置为”…/{threadGroupName}.csv”即可.

  • 当前线程

    在CSV Data Set Config配置元件作用域范围内的所有线程组,当JMeter执行测试时,每一个线程
    都单独打开一次数据源文件(可以是相同或不同的数据源文件).
    每个线程都是从数据源文件的起始处读取参数值.

    若要线程组读取不同的数据源文件,可以对数据源文件的路径进行参数化.
    这里需要使用{threadNum}来获取线程编号.
    假设有n个线程,线程编号为:1,2,…,n
    每个线程对应一个数据源文件,对应的文件名分别为: testdata1.csv,testdata2.csv,…,testdatan.csv
    在配置时将”Filename”设置为”…/testdata{threadNum}.csv”即可

2.5 可能遇到的瓶颈

  1. 网络限制:因为Metersphere服务部署在内网云,所以搞压力测试的时候,需要考虑内网访问被压服务的网络情况,内网出口带宽是否有限制。
  2. 服务器性能限制:压力测试在线程数量比较高、请求比较复杂数据量大的情况下,对客户端设备的性能亦有一定要求。
  3. 软件层面的内存限制:Metersphere的压力测试是基于Jmeter的,而Jmeter在启动时会通过配置的方式配置可以申请的最大内存,我个人本地的Jmeter是申请了较大的上限,但Metersphere如果使用默认的上限,很容易就会摸到内存瓶颈。