性能测试工具 Jmeter 做 Http 接口测试 1:编写自定义函数

pengshenshen · March 15, 2018 · Last by pengshenshen replied at April 18, 2018 · 3099 hits

开发Jmeter自定义函数

一、 前言

Jmeter提供了一组函数可以帮我们在做性能测试的时候更好的做参数化,比如字符编码格式转换、读取运行时变量值等等。但是有时候我们需要根据业务进行自定义的函数开发。

比如最近一个项目,在发送http请求的时候,客户端需要发Token,它是根据给项目分配的ID和Key值以及系统当前时间生成的,服务端会验证该Token的有效性。

开发自定义函数,网上一般有两种做法:

  • 修改jmeter源码,增加一个函数,重新导出jmeter的jar包,放入jmeter的lib目录。
  • 新建一个项目,导入jmeter原生jar包,继承虚基类,编写新函数,打包,放入jmeter的lib目录。

第一种方法既复杂,又不易于维护管理,我个人喜欢用第二种方法。

第二种方法的大坑就是package命名有特殊的要求:package路径中必须包含functions一级。

二、 编写自定义函数的步骤

1. 新建一个工程,导入jmeter jar包。

我用maven管理项目,因此只需要在pom文件中加入以下引用。

<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_java</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_core</artifactId>
<version>3.0</version>
</dependency>
2. 新建package:stressTest.functions

注意:路径中必须包含functions,否则jmeter无法识别。JMeter设计让一些核心的类(非UI相关的,比如ApacheJMeter_core等)可以在非UI的方式下运行的时候能被加载进来,这些类会被优先加载。加载这些类的时候是通过命名规则来实现的。所有实现function的类必需包含".functions."。
当然也可以通过更改jmeter.properties中的配置来实现改变命名规则,如下所示。但是一般来说不推荐更改此项配置。

classfinder.functions.contain=.functions.
3. 新建一个类继承AbstractFunction,重写以下方法:
  • execute
  • setParameters
  • getReferenceKey
  • getArgumentDesc

这四个方法介绍如下:

public String execute(SampleResult previousResult, Sampler currentSampler) throws InvalidVariableException

JMeter会将上次运行的SampleResult和当前的Sampler作为参数传入到该方法里,返回值就是在运行该function后得到的值,以String类型返回。该方法如果操作了非线程安全的对象(比如文件),则需要将对该方法进行线程同步保护。

public void setParameters(Collection<CompoundVariable> parameters) throws InvalidVariableException;

这个方法在用于传递用户在执行过程当中传入的实际参数值。该方法在function没有参数情况下也会被调用。一般该方法传入的参数会被保存在类内全局变量里,并被后面调用的execute方法中使用到。

public String getReferenceKey();

这个就是function的名字。JMeter的命名规则是在方法名前面加入双下划线"__"。比如"__GetEven",function的名字跟实现该类的类名应该一致,而且该名字应该以static final的方式在实现类中定义好,避免在运行的时候更改它。

public List<String> getArgumentDesc();

最后在你的实现类中还需要提供一个方法来告诉JMeter关于你实现的function的描述。

我自己编写的GetToken类如下:

package stressTest.functions;

import org.apache.jmeter.engine.util.CompoundVariable;
import org.apache.jmeter.functions.AbstractFunction;
import org.apache.jmeter.functions.InvalidVariableException;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.samplers.Sampler;
import org.apache.jmeter.util.JMeterUtils;
import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.util.encoders.Hex;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

/**
* Created by pengshenshen on 2018/3/12.
*/

public class GetToken extends AbstractFunction {

private static final List<String> desc = new LinkedList<String>();
private static final String KEY = "__getToken";
private CompoundVariable[] values;

// Number of parameters expected - used to reject invalid calls
private static final int MIN_PARAMETER_COUNT = 2;
private static final int MAX_PARAMETER_COUNT = 3;

static {
desc.add(JMeterUtils.getResString("appId"));
desc.add(JMeterUtils.getResString("apiKey"));
}

@Override
public String execute(SampleResult sampleResult, Sampler sampler) throws InvalidVariableException {
String appId = values[0].execute();
String apiKey = values[1].execute();
long currentTimeMillis = System.currentTimeMillis();
// 5 minutes
currentTimeMillis = currentTimeMillis - (currentTimeMillis % (1000 * 60 * 5));
byte[] data = (appId + apiKey + currentTimeMillis).getBytes();
MD5Digest md5 = new MD5Digest();
md5.update(data, 0, data.length);
byte[] digest = new byte[md5.getDigestSize()];
md5.doFinal(digest, 0);
return Hex.toHexString(digest);
}

@Override
public void setParameters(Collection<CompoundVariable> parameters) throws InvalidVariableException {
checkParameterCount(parameters, MIN_PARAMETER_COUNT, MAX_PARAMETER_COUNT);
values = parameters.toArray(new CompoundVariable[parameters.size()]);
}

@Override
public String getReferenceKey() {
return KEY;
}

@Override
public List<String> getArgumentDesc() {
return desc;
}
}

4. 打包

我用maven-assembly-plugin打包。方法如下:
首先在pom文件中引入插件:

<plugin>
<artifactId>maven-assembly-plugin</artifactId><configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>

然后执行打包命令:mvn clean compile assembly:single

5. 将打出来的jar包拷贝至jmeter的目录:

将打出来的jar包拷贝至jmeter的目录:Jmerter_HOME\lib\ext

6. 运行

Jmerter_HOME\bin\jmeter.bat,在函数助手界面中可以找到我的函数:

7. 测试

随便做一个post请求,测试该方法是否有效

向百度发一个post请求,查看一下body里面传getToken函数的结果

如图:在查看结果树中看到:请求的body中已经带了Token值。

以上函数介绍部分参照:https://www.jianshu.com/p/a88e5cb1d6cb (这个作者有产出不少jmeter的文章,在此标明出处,以后也可以慢慢看)

共收到 5 条回复 时间 点赞

沙发,顶顶~~

林小五 回复

喵喵~

第6和第7点里面的图片挂了,修复下?

陈恒捷 回复

多谢,可能是图片引的外链不稳定,重新上传了。

记录一下,assembly插件有个bug,打包时管理的spring的xsd文件有问题,会导致spring启动时在不联网的情况下找不到一些xsd文件(联网的情况下会联网找,没有问题)
具体描述如:http://chenzhou123520.iteye.com/blog/1706242
因此后来我都换shade插件了。

需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up