前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Jmeter函数分类及自定义开发

Jmeter函数分类及自定义开发

原创
作者头像
smooth00
修改2020-05-29 14:24:42
2.1K0
修改2020-05-29 14:24:42
举报
文章被收录于专栏:smooth性能之光smooth性能之光

Jmeter强大之处是其开源性和可扩展性,所以Jmeter拥有大量丰富的插件和元件,还有各种好用的函数,如果能巧妙应用函数助手里的函数,就能让性能测试脚本插上翅膀,实现各种复杂的计算和逻辑应用场景。

以下是我整理的各个版本所启用的函数(可能也会有一点出入,欢迎大家指正),这些函数在不同的jmeter版本中启用,所以jmx脚本的兼容性一定要考虑到这些因素(如果函数一但不能被解析,就会出问题),以下列表只是说明了函数的作用,具体使用方法可以见Jmeter函数助手(主要是参数及相关格式要搞清楚):

函数类型

函数名称

函数作用

启用版本

获取信息函数

__TestPlanName

返回当前测试计划的名称,调用 ${__TestPlanName}

__threadGroupName

返回当前线程组的名称

4.1

__threadNum

返回当前正在执行的线程的编号

1.X

__samplerName

返回当前请求的名称

2.5

__log

输出日志信息,示例 ${__log(报错了,ERR,,)},另一个简化的函数__logn,少了第四个参数[日志注释]

2.2

__machineName

获取当前机器名称,调用${__machineName()}

2.2

__machineIP

获取当前机器IP,调用${__machineIP()}

2.2

__time

以多种格式返回当前时间,默认13位时间戳如 ${__time(,)}

2.2

__timeShift

可对日期时间进行移位加减操作,包含5个参数(格式,日期,移位,语言环境,存储变量);举例 ${__timeShift(dd/MM/yyyy,,P-1D,,)}表示以指定格式创建当前日期,减去一天

4.0

数据输入函数

__StringFromFile

从文本文件中读取字符串,每次调用读取一行

1.9

__FileToString

把文件读取成一个字符串,每次调用都是读取整个文件

2.4

__CSVRead

读取参数文件的值,如读取第一列的参数 ${__CSVRead(D:\jmeter\login.txt,0)}

1.9

__XPath

使用 XPath 语法匹配 XML文件

2.0

__evel

返字符串表达式的结果。可以在一个变量中插入一个有值的字符串表达式或函数或变量,比如变量嵌套:举例${__evel{你好$id}},其中id来自txt参数文件,文件中的id第一行为1${__UUID},第二行2${__UUID},以此类推

2.0

__evelVar

作用同evel,只是参数不是表达式,是变量名,这个变量的值允许含表达式或函数或变量,如 ${__evalVar(SQL)}

2.0

__V

嵌套函数,作用类似于__evel,支持在变量中嵌套变量,如 ${__V(userName_${no},)}

2.0

数据计算函数

__counter

计数器函数

1.9

__intSum

对多个整数求和,如:${__intSum(${year},-1,)}

1.8.1

__longSum

长整型求和

2.3.2

__Random

返回指定最大值和最小值之间的随机整数

1.9

__RandomDate

返回给定开始日期和结束日期值之间的随机日期

3.3

__RandomString

根据给定的字符生成指定长度的随机字符串

2.6

__RandomFromMultipleVars

从多个变量中随机取一个变量值,用|号分隔变量

3.2

__dateTimeConvert

提供两种时间格式的快速转换,举例:${__dateTimeConvert(01 Jan 2017,dd MMM yyyy,dd/MM/yyyy,)}

4.0

__UUID

通用唯一标识符函数,如${__UUID}

2.9

__digest

加密计算,支持MD5、SHA等;如:${__digest(MD5,Apache JMeter 4.0 rocks !,,,)}

4.0

__char

ASCII码/十进制 转 字符,如:${__char(97)}输出a

4.0

属性信息函数

__isPropDefined

判断属性是否存在

4.0

__setProperty

用于动态设置JMeter属性,一般用于不同线程组之间传递变量,如将旧变量保存为全局变量:${__setProperty(new_var,${old_var},false)}

2.0

__property

获取属性值的函数,支持将结果另存为变量,如 ${__property(START.MS,新变量,默认值)}

1.8.1

__P

简化的获取属性值函数,用于与命令行上定义的属性一起使用,不支持另存为变量,如 ${__P(START.MS,默认值)}

2.0

字符串操作函数

__split

根据分隔符拆分字符串为多个变量,如${__split(1\,2\,3\,4,var,\,)} 逗号分隔符用\转义,分解完var_1表示第一个值1

2.0.2

__changeCase

转换大小写,如转为小写${__changeCase(ABC,LOWER,)}

4.0

__regexFunction

使用正则表达式解析之前的响应结果(一般不用它,用正则表达式提取器),包含6个参数,具体使用见[这里]

1.X

__escapeHtml

转换为HTML格式的字符,支持HTML 4.0实体,对应反传函数为__unescapeHtml;类似函数还有__escapeXml

2.0

__urlencode

将字符串进行url转码;对应的解码函数是__urldecode

2.0

__unescape

去除字符串中的转义符

2.0

脚本函数

__BeanShell

参数为beanshell脚本表达式,如${__BeanShell(123*456,)}:返回56088;${__BeanShell(source("function.bsh",))}:执行function.bsh代码;

1.X

__groovy

参数为groovy脚本表达式,如${__groovy(123*456,)}:返回56088;${__groovy(${num}%2==1)}:实现if控制;

1.X

__javaScript

执行 js 脚本,涉及逗号要用\转义,变量要用""包含,如:${__javaScript('${var}'.slice(2\,4))}

1.9

__jexl

使用Jexl表达式引擎解析,包括两个版本__jexl2和__jexl3,如${__jexl3(${num}<10)}也相当于if控制

1.9

验证信息函数

__isVarDefined

测试属性是否可用,如:${__isPropDefined(START.HMS)}返回true

4.0

__isPropDefined

测试变量是否可用,如:${__isVarDefined(JMeterThread.last_sample_ok)} 返回true

4.0

除了Jmeter原装的函数,大家还喜欢用到第三方的JMeterPlugins插件,比如JMeterPlugins-ExtrasLibs,这里面还带一些扩展的函数,一般使用率不高,但是其中的__env获取环境变量,__chooseRandom随机选取值,我们用的也比较多:

函数类型

函数名称

函数作用

版本

获取信息函数

__env

获取系统环境变量值,如${__env(JAVA_HOME,newName,C:\jdk1.8)}

1.2

__iterationNum

获取循环迭代号,如${__iterationNum}

1.2

数据计算函数

__base64Encode

将字符串进行base64位编码,对应的解码函数为__base64Decode

1.2

__chooseRandom

枚举随机数,从多个数值或字符串中随机取值,用逗号分隔,最后一个逗号后面为空或是变量名。举例:${__chooseRandom(A1,B2,C3,D4,)},随机4选1返回

1.2

__doubleSum

符点型求和

1.2

__MD5

MD5串生成,如 ${__MD5(12345,)} 返回12345的md5加密串

1.2

字符串操作函数

__lowercase

将字符串转为小写字母,如${__lowercase(ABC,)}

1.2

验证信息函数

__isDefined

测试属性或变量是否可用,如:${__isDefined(START.HMS)}返回1

1.2

除了用到Jmeter自带的函数,以及JMeterPlugins插件所带有的函数,我们还可以进行自定义函数的开发:

在package org.apache.jmeter.functions;中增加自定义函数,代码模板如下:

代码语言:javascript
复制
package org.apache.jmeter.functions;

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

import org.apache.jmeter.engine.util.CompoundVariable;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.samplers.Sampler;

public class MyFrisFuncion extends AbstractFunction{
	private static final List<String> desc = new LinkedList<String>();
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

	@Override
	public List<String> getArgumentDesc() {
		/**
		* Return a list of strings briefly describing each parameter your function
		* takes. Please use JMeterUtils.getResString(resource_name) to grab a
		* resource string. Otherwise, your help text will be difficult to
		* internationalize.
		*
		* This list is not optional. If you don't wish to write help, you must at
		* least return a List containing the correct number of blank strings, one
		* for each argument.
		* @return List with brief descriptions for each parameter the function takes
		*/
		//本方法简要描述函数的每个参数,使用JMeterUtils.getResString可获取中文资源字符串
		//中文描述资源文件路径为 bin/core/org/apache/jmeter/resources/messages_zh_CN.properties
		return desc;
	}
	
	@Override
	public String execute(SampleResult arg0, Sampler arg1) throws InvalidVariableException {
		/**
		* Given the previous SampleResult and the current Sampler, return a string
		* to use as a replacement value for the function call. Assume
		* "setParameter" was previously called.
		*
		* This method must be threadsafe - multiple threads will be using the same
		* object.
		* @param previousResult The previous {@link SampleResult}
		* @param currentSampler The current {@link Sampler}
		* @return The replacement value, which was generated by the function
		* @throws InvalidVariableException - when the variables for the function call can't be evaluated
		*/
		//本方法是提供一个在Jmeter调用的函数入口
		return "Jmeter函数";
	}
	
	@Override
	public String getReferenceKey() {
		/**
		* Return the name of your function. Convention is to prepend "__" to the
		* name (ie "__regexFunction")
		* @return The name of the function
		*/
		//本方法是提供一个在Jmeter函数助手显示的函数名称
		return "__NewFunction";
	}

	@Override
	public void setParameters(Collection<CompoundVariable> arg0) throws InvalidVariableException {
		/**
		* A collection of the parameters used to configure your function. Each
		* parameter is a CompoundVariable and can be resolved by calling the
		* execute() method of the CompoundVariable (which should be done at
		* execution.)
		*
		* @param parameters The parameters for the function call
		* @throws InvalidVariableException - when the variables for the function call can't be evaluated
		*/
		//本方法是设置函数参数使用的!checkParameterCount是校验参数数量
		//以下第2个参数为MIN_PARAM_COUNT,第3个参数为MAX_PARAM_COUNT,两者差值就是可选参数数量
		checkParameterCount(arg0, 0, 0); // 都是0表示无入参
	}	
}

2、重构以上代码并打成jar包

(1)创建自定义函数__RandomEmail

代码语言:javascript
复制
package org.smooth.jmeter.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.smooth.jmeter.functions.core.RandomString;

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

/**
 * 随机生成电子邮箱
 * @author smooth
 * @date 2019-12-02 13:15
 */
@SuppressWarnings("unchecked")
public class RandomEmail extends AbstractFunction {

    @Override
    public String execute(SampleResult sampleResult, Sampler sampler) throws InvalidVariableException {
        return RandomString.getEmail();
    }

    @Override
    public void setParameters(Collection<CompoundVariable> collection) throws InvalidVariableException {
        checkParameterCount(collection, 0, 0);
    }
    /**
     * 提供jmeter函数助手显示的下来选项名称
     **/
    @Override
    public String getReferenceKey() {
        return "__RandomEmail";
    }

    public List<String> getArgumentDesc() {
        return new LinkedList();
    }
}

其中电子邮箱随机生成的代码如下:

代码语言:javascript
复制
package org.smooth.jmeter.functions.core;

/**
 * @author smooth00
 * @date 2019-12-02 11:21
 */
public class RandomString {

    /** 普遍随机字符串来源 */
    private static final String[] SOURCE_STRING = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".split("|");
    /** 常用邮箱后缀 */
    private static final String EMAIL_SUFFIX = "@gmail.com, @yahoo.com, @msn.com, @hotmail.com, @aol.com, @ask.com, @live.com, @qq.com, @0355.net, @163.com, @163.net, @263.net, @3721.net, @yeah.net, @googlemail.com, @126.com, @sina.com, @sohu.com, @yahoo.com.cn";

     /**
     * 获取0到指定数值间的随机数,内部使用
     * @param max
     * @return
     */
    private static int getRandomNum(int max) {
        if (max < 0) {
            throw new RuntimeException("最大值需要大于或等于0");
        }
        return (int) (Math.random() * max);
    }

    /**
     * 返回[0-9,a-z,A-Z]的随机字符串
     * @param len 字符串长度
     * @return
     */
    public static String getFixed(int len) {
        StringBuilder resBuf = new StringBuilder();
        for (int i = 0; i < len; i++) {
            int randIndex = getRandomNum(SOURCE_STRING.length);
            resBuf.append(SOURCE_STRING[randIndex]);
        }
        return resBuf.toString();
    }

    /**
     * 生成随机指定范围的定长字符串
     *
     * @param src 产生随机字符串来源,使用英文逗号分开
     * @param len 返回字符串长度
     * @return
     */
    public static final String getRange(String src, int len) {
        if (src == null || src.length() == 0) {
            throw new RuntimeException("来源字符串为空");
        }
        if (len < 1) {
            throw new RuntimeException("返回字符串长度需要大于0");
        }
        String[] arr = src.split(",");
        StringBuffer buf = new StringBuffer();
        for (int i = 0; i < len; i++) {
            int index = getRandomNum(arr.length);
            buf.append(arr[index].trim());
        }
        return buf.toString();
    }

    /**
     * 生成随机电子邮箱
     * @return
     */
    public static String getEmail() {
        // 生成用户名 6-16 位长度
        int len = getRandomNum(10) + 6;
        String userName = getFixed(len).toLowerCase();
        String email = getRange(EMAIL_SUFFIX, 1);
        return userName + email;
    }
}

(2)Maven Build生成jar包,

(3)将jar包拷贝至$JMETER__HOME/lib/ext目录下,重启Jmeter

3、在Jmeter的函数助手中看到新增的函数,并调试通过

4、具体代码我已发布,可以参考 https://gitee.com/smooth00/jmeter-ExtraFunc-plugins

代码结构:

代码语言:javascript
复制
jmeter-ExtraFunc-plugins
├─src
│  └─main
│     ├─java
│     └─resources
├─pom.xml

开发说明:

  • 1、Jmeter插件必须在包含.functions包下
  • 2、创建一个类,继承org.apache.jmeter.functions.AbstractFunction,重写下面方法:
代码语言:javascript
复制
/** 函数执行逻辑,并返回值 */
public String execute(SampleResult sampleResult, Sampler sampler);
/** 接受处理入参 */
public void setParameters(Collection<CompoundVariable> collection);
/** 定义返回函数名称 */
public String getReferenceKey();
/** 定义函数入参说明 */
public List<String> getArgumentDesc();

欢迎光临我的博客:https://smooth.blog.csdn.net/

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档