Jmeter JSON Config Element插件开发_jmeter插件开发-程序员宅基地

技术标签: java  Jmeter  json  html  

目录

背景:

 简单介绍一下:

文件名:即读取的json文件路径,json数组

文件编码:即文件读取时的编码

JSON Path 表达式:用来提取JSON数据文件中的

Variable Names:在Jmeter上下文引用的变量

主要步骤如下

1、选择一个包并编写三个文件:

[组件名称].java (jmeter.config.JSONDataSet.java)

[组件名称]BeanInfo.java (jmeter.config.JSONDataSetBeanInfo.java)

[组件名称]Resources.properties (org.apache.jmeter.config.JSONDataSetResources.properties)

2、JSONDataSet.java必须实现TestBean接口。

3、JSONDataSetBeanInfo.java应该扩展org.apache.jmeter.testbeans.BeanInfoSupport

4、实现逻辑。

具体逻辑实现如下:

在JSONDataSetBeanInfo 中设置 GUI 元素:

定义资源字符串。

详细的资源定义如下:

Pom文件如下:


背景:

在项目中有个场景需要从json文件中读取数据来并且进行引用,想法是做成和CSV Data Set Config类似,可以从json文件(json数组)中循环读取数据,并且通过JsonPath(使用fastjson的JSONPath类来提取数据)来提取与之匹配的值,提取之后可以在当前线程或者其他线程进行引用。界面如下:

 

 简单介绍一下:

文件名:即读取的json文件路径,json数组

文件编码:即文件读取时的编码

JSON Path 表达式:用来提取JSON数据文件中的

Variable Names:在Jmeter上下文引用的变量

主要步骤如下

1、选择一个包并编写三个文件:

[组件名称].java (jmeter.config.JSONDataSet.java)

[组件名称]BeanInfo.java (jmeter.config.JSONDataSetBeanInfo.java)

[组件名称]Resources.properties (org.apache.jmeter.config.JSONDataSetResources.properties)

如下图:

其中[组件名称]BeanInfo.java 表示Config Element的界面,如本例中的JSONDataSet BeanInfo;[组件名称].java 表示插件的处理逻辑,如本例中的JSONDataSet.java;[组件名称]Resources.properties表示界面显示的文字,同如本例相关文件。

2、JSONDataSet.java必须实现TestBean接口。

此外,它将扩展 ConfigTestElement,并实现LoopIterationListener。(不需要迭代的不用实现)TestBean是一个标记接口,因此没有要实现的方法。扩展ConfigTestElement将使我们的组件成为测试计划中的Config元素。

3、JSONDataSetBeanInfo.java应该扩展org.apache.jmeter.testbeans.BeanInfoSupport

创建一个零参数构造函数,我们在其中调用super(CSVDataSet.class);

4、实现逻辑。

该JSONDataSet将读取一个json数组文件,并会保存它发现到JMeter的运行范围内使用JSONPath匹配的值。为每个要引用的值定义变量名称。实现TestBean 时,请注意属性。这些属性将成为用户配置JSONDataSet元素的 GUI 表单的基础。

测试开始时,JMeter 将克隆您的元素。每个线程都会得到它自己的实例。但是,如果需要,您将有机会控制克隆的完成方式。

variableNames是一个字符串,它允许用户输入我们将为其赋值的变量的名称。为什么是字符串?为什么不是一个集合?用户肯定需要输入多个(和未知数量的)变量名称吗?是的,但是如果我们使用 List 或 Collection,我们就必须编写一个 GUI 组件来处理集合,而我只想快速完成。相反,我们将让用户输入以逗号分隔的变量名称列表。

然后我实现了LoopIterationListener接口的IterationStart方法。这个“事件”的重点是当测试进入它的父控制器时通知你的组件。出于我们的目的,每次输入JSONDataSet的父控制器时,我们都会读取数据文件的新对象并设置变量。因此,对于常规控制器,每次测试循环都会导致读取一组新值。对于循环控制器,每次迭代都会这样做。每个测试线程也会得到不同的值。

具体逻辑实现如下:

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package jmeter.config;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.config.ConfigTestElement;
import org.apache.jmeter.engine.event.LoopIterationEvent;
import org.apache.jmeter.engine.event.LoopIterationListener;
import org.apache.jmeter.testbeans.TestBean;
import org.apache.jmeter.testbeans.gui.GenericTestBeanCustomizer;
import org.apache.jmeter.testelement.property.JMeterProperty;
import org.apache.jmeter.testelement.property.StringProperty;
import org.apache.jmeter.threads.JMeterContext;
import org.apache.jmeter.threads.JMeterVariables;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.util.JMeterStopThreadException;
import org.apache.jorphan.util.JOrphanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.io.*;
import java.util.*;

/**
 * Read lines from a file and split int variables.
 * <p>
 * The iterationStart() method is used to set up each set of values.
 * <p>
 * By default, the same file is shared between all threads
 * (and other thread groups, if they use the same file name).
 * <p>
 * The shareMode can be set to:
 * <ul>
 * <li>All threads - default, as described above</li>
 * <li>Current thread group</li>
 * <li>Current thread</li>
 * <li>Identifier - all threads sharing the same identifier</li>
 * </ul>
 * <p>
 * The class uses the FileServer alias mechanism to provide the different share modes.
 * For all threads, the file alias is set to the file name.
 * Otherwise, a suffix is appended to the filename to make it unique within the required context.
 * For current thread group, the thread group identityHashcode is used;
 * for individual threads, the thread hashcode is used as the suffix.
 * Or the user can provide their own suffix, in which case the file is shared between all
 * threads with the same suffix.
 */

public class JSONDataSet extends ConfigTestElement
        implements TestBean, LoopIterationListener {
    private static final Logger log = LoggerFactory.getLogger(JSONDataSet.class);

    private static final long serialVersionUID = 233L;

    private static final String EOFVALUE = // value to return at EOF
            JMeterUtils.getPropDefault("jsondataset.eofstring", "<EOF>"); //$NON-NLS-1$ //$NON-NLS-2$

    private transient String filename;

    private transient String fileEncoding;

    private transient String variableNames;


    private transient String jsonpathExpression;

    private transient boolean recycle = true;

    private transient boolean stopThread;

    private transient String[] vars;

    private transient String[] jsonPathVars;

//    private transient String alias;

    private transient String shareMode;


    /**
     * @return Returns the filename.
     */
    public String getFilename() {
        return filename;
    }

    /**
     * @param filename The filename to set.
     */
    public void setFilename(String filename) {
        this.filename = filename;
    }

    /**
     * @return Returns the file encoding.
     */
    public String getFileEncoding() {
        return fileEncoding;
    }

    /**
     * @param fileEncoding The fileEncoding to set.
     */
    public void setFileEncoding(String fileEncoding) {
        this.fileEncoding = fileEncoding;
    }

    /**
     * @return Returns the variableNames.
     */
    public String getVariableNames() {
        return variableNames;
    }

    /**
     * @param variableNames The variableNames to set.
     */
    public void setVariableNames(String variableNames) {
        this.variableNames = variableNames;
    }

    public String getJsonpathExpression() {
        return jsonpathExpression;
    }

    public void setJsonpathExpression(String jsonpathExpression) {
        this.jsonpathExpression = jsonpathExpression;
    }

    public boolean getRecycle() {
        return recycle;
    }

    public void setRecycle(boolean recycle) {
        this.recycle = recycle;
    }

    public boolean getStopThread() {
        return stopThread;
    }

    public void setStopThread(boolean value) {
        this.stopThread = value;
    }

    public String getShareMode() {
        return shareMode;
    }

    public void setShareMode(String value) {
        this.shareMode = value;
    }


    private Object readResolve() {
        recycle = true;
        return this;
    }

    /**
     * Override the setProperty method in order to convert
     * the original String shareMode property.
     * This used the locale-dependent display value, so caused
     * problems when the language was changed.
     * If the "shareMode" value matches a resource value then it is converted
     * into the resource key.
     * To reduce the need to look up resources, we only attempt to
     * convert values with spaces in them, as these are almost certainly
     * not variables (and they are definitely not resource keys).
     */
    @Override
    public void setProperty(JMeterProperty property) {
        if (property instanceof StringProperty) {
            final String propName = property.getName();
            if ("shareMode".equals(propName)) { // The original name of the property
                final String propValue = property.getStringValue();
                if (propValue.contains(" ")) { // variables are unlikely to contain spaces, so most likely a translation
                    try {
                        final BeanInfo beanInfo = Introspector.getBeanInfo(this.getClass());
                        final ResourceBundle rb = (ResourceBundle) beanInfo.getBeanDescriptor().getValue(GenericTestBeanCustomizer.RESOURCE_BUNDLE);
                        for (String resKey : JSONDataSetBeanInfo.getShareTags()) {
                            if (propValue.equals(rb.getString(resKey))) {
                                if (log.isDebugEnabled()) {
                                    log.debug("Converted {}={} to {} using Locale: {}", propName, propValue, resKey, rb.getLocale());
                                }
                                ((StringProperty) property).setValue(resKey); // reset the value
                                super.setProperty(property);
                                return;
                            }
                        }
                        // This could perhaps be a variable name
                        log.warn("Could not translate {}={} using Locale: {}", propName, propValue, rb.getLocale());
                    } catch (IntrospectionException e) {
                        log.error("Could not find BeanInfo; cannot translate shareMode entries", e);
                    }
                }
            }
        }
        super.setProperty(property);
    }

    @Override
    public void iterationStart(LoopIterationEvent iterEvent) {
//        FileServer server = FileServer.getFileServer();
        final JMeterContext context = getThreadContext();//Jmeter 上下文
        int index = 0;
        if (vars == null) {
            String fileName = getFilename().trim();

            String mode = getShareMode();
            int modeInt = JSONDataSetBeanInfo.getShareModeAsInt(mode);
//            switch (modeInt) {
//                case JSONDataSetBeanInfo.SHARE_ALL:
//                    alias = fileName;
//                    break;
//                case JSONDataSetBeanInfo.SHARE_GROUP:
//                    alias = fileName + "@" + System.identityHashCode(context.getThreadGroup());
//                    break;
//                case JSONDataSetBeanInfo.SHARE_THREAD:
//                    alias = fileName + "@" + System.identityHashCode(context.getThread());
//                    break;
//                default:
//                    alias = fileName + "@" + mode; // user-specified key
//                    break;
//            }

            //获取引用的变量
            final String names = getVariableNames();//引用变量
            final String jsonNames = getJsonpathExpression();
            if (!StringUtils.isEmpty(names)) {
//                server.reserveFile(fileName, getFileEncoding(), alias);
                // 提取引用变量到数组
                vars = JOrphanUtils.split(names, ",");
                log.info("===============================================" + vars.toString());
                //提取JsonPath变量并存到数组
                jsonPathVars = JOrphanUtils.split(jsonNames, ",");
                log.info("jsonPathVars数组长度为:" + jsonPathVars.length);

            } else {
                throw new IllegalArgumentException("Could not split JSON Path Expression line from file:" + fileName);
            }
            trimVarNames(vars);

            //获取数据
            // TODO: fetch this once as per vars above?
            JMeterVariables threadVars = context.getVariables();

            String[] jsonLineValues = {};//存取使用JsonPath提取后的值
            //分割JsonPath表达式提取的值并存到数组
            jsonLineValues = JOrphanUtils.split(jsonNames, ",", false);
            log.info("===============================================" + fileName);
            String jsonFile = readJsonFile(fileName);
            //从json输入文件中,读取一个Json对象

            JSONArray jsonArray = JSON.parseArray(jsonFile);

            log.info("***************************index: " + "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" + iterEvent.getIteration());

            System.out.println("============================********************" + threadVars.getIteration());
            String num=threadVars.getThreadName().split("-")[1];
            index=Integer.parseInt(num);
            JSONObject jsonObject = jsonArray.getJSONObject(index);

            String line = jsonObject.toJSONString();

            log.info("===" + line);
            String jsonValue;

            for (int i = 0; i < jsonPathVars.length; i++) {
                log.info("i " + i + "==========================");
                log.info("i: " + jsonPathVars[i]);
                jsonValue = JSONPath.read(line, jsonPathVars[i]).toString();

                jsonLineValues[i] = jsonValue;
            }

            //提取Json Path匹配的值,经过jsonpath转换的值
//        lineValues = JOrphanUtils.split(line, ",", false);

            for (int a = 0; a < vars.length && a < jsonLineValues.length; a++) {
                threadVars.put(vars[a], jsonLineValues[a]);
            }

            if (jsonLineValues.length == 0) {// i.e. EOF
                if (getStopThread()) {
                    throw new JMeterStopThreadException("End of file:" + getFilename() + " detected for JSON DataSet:"
                            + getName() + " configured with stopThread:" + getStopThread() + ", recycle:" + getRecycle());
                }
                for (String var : vars) {
                    threadVars.put(var, EOFVALUE);
                }
            }

            threadVars.incIteration();
        }

    }

    /**
     * trim content of array varNames
     *
     * @param varsNames
     */
    private void trimVarNames(String[] varsNames) {
        for (int i = 0; i < varsNames.length; i++) {
            varsNames[i] = varsNames[i].trim();
        }
    }

    //读取json文件
    public static String readJsonFile(String fileName) {
        String jsonStr = "";
        try {
            File jsonFile = new File(fileName);
            FileReader fileReader = new FileReader(jsonFile);
            Reader reader = new InputStreamReader(new FileInputStream(jsonFile), "utf-8");
            int ch = 0;
            StringBuffer sb = new StringBuffer();
            while ((ch = reader.read()) != -1) {
                sb.append((char) ch);
            }
            fileReader.close();
            reader.close();
            jsonStr = sb.toString();
            return jsonStr;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

}

在JSONDataSetBeanInfo 中设置 GUI 元素:

我们可以为组件的属性创建分组。创建的每个分组都需要一个标签和要包含在该分组中的属性名称列表。IE:

createPropertyGroup("json_data",             //$NON-NLS-1$
        new String[]{FILENAME, FILE_ENCODING, JSONPATH_EXP,VARIABLE_NAMES,
                RECYCLE, STOPTHREAD, SHAREMODE});

创建分组称为json_data,其中将包括在GUI上的输入元件 的文件名和variableNames的性质JSONDataSet。然后,我们需要定义我们希望这些属性的类型:

PropertyDescriptor p = property(FILENAME);
p.setValue(NOT_UNDEFINED, Boolean.TRUE);
p.setValue(DEFAULT, "");        //$NON-NLS-1$
p.setValue(NOT_EXPRESSION, Boolean.TRUE);
p.setPropertyEditorClass(FileEditor.class);

p = property(FILE_ENCODING, TypeEditor.ComboStringEditor);
p.setValue(NOT_UNDEFINED, Boolean.TRUE);
p.setValue(DEFAULT, "");        //$NON-NLS-1$
p.setValue(TAGS, getListFileEncoding());

//jsonpath表达式用","分隔
p = property(JSONPATH_EXP);
p.setValue(NOT_UNDEFINED, Boolean.TRUE);
p.setValue(DEFAULT, "");        //$NON-NLS-1$
p.setValue(NOT_EXPRESSION, Boolean.TRUE);

p = property(VARIABLE_NAMES);
p.setValue(NOT_UNDEFINED, Boolean.TRUE);
p.setValue(DEFAULT, "");        //$NON-NLS-1$
p.setValue(NOT_EXPRESSION, Boolean.TRUE);


p = property(RECYCLE);
p.setValue(NOT_UNDEFINED, Boolean.TRUE);
p.setValue(DEFAULT, Boolean.TRUE);

p = property(STOPTHREAD);
p.setValue(NOT_UNDEFINED, Boolean.TRUE);
p.setValue(DEFAULT, Boolean.FALSE);

p = property(SHAREMODE, TypeEditor.ComboStringEditor);
p.setValue(RESOURCE_BUNDLE, getBeanDescriptor().getValue(RESOURCE_BUNDLE));
p.setValue(NOT_UNDEFINED, Boolean.TRUE);
p.setValue(DEFAULT, SHARE_TAGS[SHARE_ALL]);
p.setValue(NOT_OTHER, Boolean.FALSE);
p.setValue(NOT_EXPRESSION, Boolean.FALSE);
p.setValue(TAGS, SHARE_TAGS);

这实质上创建了7个属性,其值不允许为null,其默认值为""。可以为每个属性设置几个这样的属性。这是一个纲要:

NOT_UNDEFINED

该属性不会保留为null。

DEFAULT

如果NOT_UNDEFINED为true ,则必须给出默认值。

NOT_EXPRESSION

如果为true ,则不会为函数解析该值。

NOT_OTHER

这不是一个自由形式的输入字段——必须提供一个值列表。

TAGS

使用String[]作为值,这将设置可接受值的预定义列表,JMeter 将创建一个下拉选择。

此外,可以为属性指定自定义属性编辑器:

p.setPropertyEditorClass(FileEditor.class);

这将创建一个文本输入和浏览按钮,该按钮打开一个用于查找文件的对话框。

详细的GUI文件定义如下:

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package jmeter.config;

import org.apache.jmeter.testbeans.BeanInfoSupport;
import org.apache.jmeter.testbeans.gui.FileEditor;
import org.apache.jmeter.testbeans.gui.TypeEditor;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.util.JOrphanUtils;

import java.beans.PropertyDescriptor;

public class JSONDataSetBeanInfo extends BeanInfoSupport {

    static final int SHARE_ALL = 0;
    static final int SHARE_GROUP = 1;
    static final int SHARE_THREAD = 2;
    // These names must agree case-wise with the variable and property names
    private static final String FILENAME = "filename";               //$NON-NLS-1$
    private static final String FILE_ENCODING = "fileEncoding";      //$NON-NLS-1$
    private static final String VARIABLE_NAMES = "variableNames";    //$NON-NLS-1$
    private static final String JSONPATH_EXP = "jsonpathExpression";
    private static final String RECYCLE = "recycle";                 //$NON-NLS-1$
    private static final String STOPTHREAD = "stopThread";           //$NON-NLS-1$
    private static final String SHAREMODE = "shareMode";             //$NON-NLS-1$
    // Access needed from CSVDataSet
    private static final String[] SHARE_TAGS = new String[3];

    // Store the resource keys
    static {
        SHARE_TAGS[SHARE_ALL] = "shareMode.all"; //$NON-NLS-1$
        SHARE_TAGS[SHARE_GROUP] = "shareMode.group"; //$NON-NLS-1$
        SHARE_TAGS[SHARE_THREAD] = "shareMode.thread"; //$NON-NLS-1$        
    }

    public JSONDataSetBeanInfo() {
        super(JSONDataSet.class);

        createPropertyGroup("json_data",             //$NON-NLS-1$
                new String[]{FILENAME, FILE_ENCODING, JSONPATH_EXP,VARIABLE_NAMES,
                        RECYCLE, STOPTHREAD, SHAREMODE});

        PropertyDescriptor p = property(FILENAME);
        p.setValue(NOT_UNDEFINED, Boolean.TRUE);
        p.setValue(DEFAULT, "");        //$NON-NLS-1$
        p.setValue(NOT_EXPRESSION, Boolean.TRUE);
        p.setPropertyEditorClass(FileEditor.class);

        p = property(FILE_ENCODING, TypeEditor.ComboStringEditor);
        p.setValue(NOT_UNDEFINED, Boolean.TRUE);
        p.setValue(DEFAULT, "");        //$NON-NLS-1$
        p.setValue(TAGS, getListFileEncoding());

        //jsonpath表达式用","分隔
        p = property(JSONPATH_EXP);
        p.setValue(NOT_UNDEFINED, Boolean.TRUE);
        p.setValue(DEFAULT, "");        //$NON-NLS-1$
        p.setValue(NOT_EXPRESSION, Boolean.TRUE);

        p = property(VARIABLE_NAMES);
        p.setValue(NOT_UNDEFINED, Boolean.TRUE);
        p.setValue(DEFAULT, "");        //$NON-NLS-1$
        p.setValue(NOT_EXPRESSION, Boolean.TRUE);


        p = property(RECYCLE);
        p.setValue(NOT_UNDEFINED, Boolean.TRUE);
        p.setValue(DEFAULT, Boolean.TRUE);

        p = property(STOPTHREAD);
        p.setValue(NOT_UNDEFINED, Boolean.TRUE);
        p.setValue(DEFAULT, Boolean.FALSE);

        p = property(SHAREMODE, TypeEditor.ComboStringEditor);
        p.setValue(RESOURCE_BUNDLE, getBeanDescriptor().getValue(RESOURCE_BUNDLE));
        p.setValue(NOT_UNDEFINED, Boolean.TRUE);
        p.setValue(DEFAULT, SHARE_TAGS[SHARE_ALL]);
        p.setValue(NOT_OTHER, Boolean.FALSE);
        p.setValue(NOT_EXPRESSION, Boolean.FALSE);
        p.setValue(TAGS, SHARE_TAGS);
    }

    public static int getShareModeAsInt(String mode) {
        if (mode == null || mode.length() == 0) {
            return SHARE_ALL; // default (e.g. if test plan does not have definition)
        }
        for (int i = 0; i < SHARE_TAGS.length; i++) {
            if (SHARE_TAGS[i].equals(mode)) {
                return i;
            }
        }
        return -1;
    }

    /**
     * @return array of String for possible sharing modes
     */
    public static String[] getShareTags() {
        String[] copy = new String[SHARE_TAGS.length];
        System.arraycopy(SHARE_TAGS, 0, copy, 0, SHARE_TAGS.length);
        return copy;
    }

    /**
     * Get the mains file encoding
     * list from https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html
     *
     * @return a String[] with the list of file encoding
     */
    private String[] getListFileEncoding() {
        return JOrphanUtils.split(JMeterUtils.getPropDefault("csvdataset.file.encoding_list", ""), "|"); //$NON-NLS-1$
    }
}

定义资源字符串。

在JSONDataSetResources.properties 中,我们必须定义所有字符串资源。为了提供翻译,可以创建其他文件,例如 JSONDataSetResources_ja.properties和JSONDataSetResources_de.properties。对于我们的组件,我们必须定义以下资源:

displayName

这将为将出现在菜单中的元素提供一个名称。

json_data.displayName

我们创建了一个名为csv_data的属性分组,因此我们必须为分组提供一个标签

filename.displayName

文件名输入元素的标签。

filename.shortDescription(当鼠标定位到GUI输入框名称提示性文字)

类似工具提示的帮助文本简介。

variableNames.displayName

变量名称输入元素的标签。

variableNames.shortDescription

variableNames输入元素的工具提示。

详细的资源定义如下:

displayName=JSON Data Set Config
#控制面板名称
json_data.displayName=Config the JSON Data Source
filename.displayName=FileName
filename.shortDescription=Name of the file that holds the json data (relative or absolute filename)
fileEncoding.displayName=File encoding
fileEncoding.shortDescription=The character set encoding used in the file
jsonpathExpression.displayName=JSON Path Expression(comma-delimited)
jsonpathExpression.shortDescription=JSON Path Expressions in order to match the order of data in your json data
variableNames.displayName=Variable Names (comma-delimited)
variableNames.shortDescription=List your variable names in order to match the order of columns in your json data. Keep it empty to use the first line of the file for variable names.
recycle.displayName=Recycle on EOF ?
recycle.shortDescription=Should the file be re-read from the start on reaching EOF ?
stopThread.displayName=Stop thread on EOF ?
stopThread.shortDescription=Should the thread be stopped on reaching EOF (if Recycle is false) ?
shareMode.displayName=Sharing mode
shareMode.shortDescription=Select which threads share the same file pointer
shareMode.all=All threads
shareMode.group=Current thread group
shareMode.thread=Current thread

Pom文件如下:

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"

         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>



    <groupId>com.test.jmeter</groupId>

    <artifactId>JmeterFunctions</artifactId>

    <version>0.0.1-SNAPSHOT</version>

    <packaging>jar</packaging>



    <name>JmeterFunctions</name>

    <url>http://maven.apache.org</url>



    <properties>

        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

    </properties>



    <repositories>



    </repositories>



    <dependencies>

        



        <dependency>

            <groupId>junit</groupId>

            <artifactId>junit</artifactId>

            <version>4.12</version>

            <scope>compile</scope>

        </dependency>

        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->

        <dependency>

            <groupId>com.alibaba</groupId>

            <artifactId>fastjson</artifactId>

            <version>1.2.73</version>

        </dependency>

        <dependency>

            <groupId>org.apache.commons</groupId>

            <artifactId>commons-lang3</artifactId>

            <version>3.4</version>

        </dependency>

        <!-- https://mvnrepository.com/artifact/com.google.zxing/zxing-parent -->



        <dependency>

            <groupId>org.apache.jmeter</groupId>

            <artifactId>ApacheJMeter_core</artifactId>

            <version>5.2.1</version>

            <exclusions>

                <exclusion>

                    <groupId>org.codehaus.groovy</groupId>

                    <artifactId>groovy-all</artifactId>

                </exclusion>

            </exclusions>

        </dependency>



        <dependency>

            <groupId>org.apache.jmeter</groupId>

            <artifactId>ApacheJMeter_java</artifactId>

            <version>5.2.1</version>

            <exclusions>

                <exclusion>

                    <groupId>org.codehaus.groovy</groupId>

                    <artifactId>groovy-all</artifactId>

                </exclusion>

            </exclusions>

        </dependency>

        <dependency>

            <groupId>org.apache.jmeter</groupId>

            <artifactId>ApacheJMeter_core</artifactId>

            <version>5.2.1</version>

        </dependency>





    </dependencies>

    <build>



        <resources>

            <resource>

                <directory>src/main/java</directory>

                <includes>

                    <include>**/*.properties</include>

                </includes>

            </resource>

            <resource>

                <directory>src/main/resources</directory>

                <includes>

                    <include>**/*.properties</include>

                </includes>

            </resource>

        </resources>





        <plugins>

            <plugin>

                <artifactId>maven-compiler-plugin</artifactId>

                <version>3.7.0</version>

                <configuration>

                    <source>1.8</source>

                    <target>1.8</target>

                </configuration>

            </plugin>



            <plugin>

                <artifactId>maven-assembly-plugin</artifactId>

                <configuration>

                    <descriptorRefs>

                        <descriptorRef>jar-with-dependencies</descriptorRef>

                    </descriptorRefs>

                    <archive>

                        <manifest>

                            <mainClass>com.test.util.GenerateSortCode</mainClass>

                        </manifest>

                    </archive>

                </configuration>

                <executions>

                    <execution>

                        <id>make-assembly</id>

                        <phase>package</phase>

                        <goals>

                            <goal>single</goal>

                        </goals>

                    </execution>

                </executions>

            </plugin>

        </plugins>

    </build>

</project>

调试组件。

 逻辑实现完后使用maven打包然后放到Jmeter\lib\ext目录下后重启Jmeter即可在Config Element中找到我们开发的JSON DataSet Config,然后可以使用json数组文件试一下,运行结果如下图:

 目前存在的问题,不能像CSV那样去一行一行的遍历json对象,想法是一次遍历一个json对象,目前还没有想到很好的办法,当前是根据线程数去访问json对象有可能产生数组越界(在Json数组比较小的时候),先记录一下流程后续再优化

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/TalorSwfit20111208/article/details/120371672

智能推荐

while循环&CPU占用率高问题深入分析与解决方案_main函数使用while(1)循环cpu占用99-程序员宅基地

文章浏览阅读3.8k次,点赞9次,收藏28次。直接上一个工作中碰到的问题,另外一个系统开启多线程调用我这边的接口,然后我这边会开启多线程批量查询第三方接口并且返回给调用方。使用的是两三年前别人遗留下来的方法,放到线上后发现确实是可以正常取到结果,但是一旦调用,CPU占用就直接100%(部署环境是win server服务器)。因此查看了下相关的老代码并使用JProfiler查看发现是在某个while循环的时候有问题。具体项目代码就不贴了,类似于下面这段代码。​​​​​​while(flag) {//your code;}这里的flag._main函数使用while(1)循环cpu占用99

【无标题】jetbrains idea shift f6不生效_idea shift +f6快捷键不生效-程序员宅基地

文章浏览阅读347次。idea shift f6 快捷键无效_idea shift +f6快捷键不生效

node.js学习笔记之Node中的核心模块_node模块中有很多核心模块,以下不属于核心模块,使用时需下载的是-程序员宅基地

文章浏览阅读135次。Ecmacript 中没有DOM 和 BOM核心模块Node为JavaScript提供了很多服务器级别,这些API绝大多数都被包装到了一个具名和核心模块中了,例如文件操作的 fs 核心模块 ,http服务构建的http 模块 path 路径操作模块 os 操作系统信息模块// 用来获取机器信息的var os = require('os')// 用来操作路径的var path = require('path')// 获取当前机器的 CPU 信息console.log(os.cpus._node模块中有很多核心模块,以下不属于核心模块,使用时需下载的是

数学建模【SPSS 下载-安装、方差分析与回归分析的SPSS实现(软件概述、方差分析、回归分析)】_化工数学模型数据回归软件-程序员宅基地

文章浏览阅读10w+次,点赞435次,收藏3.4k次。SPSS 22 下载安装过程7.6 方差分析与回归分析的SPSS实现7.6.1 SPSS软件概述1 SPSS版本与安装2 SPSS界面3 SPSS特点4 SPSS数据7.6.2 SPSS与方差分析1 单因素方差分析2 双因素方差分析7.6.3 SPSS与回归分析SPSS回归分析过程牙膏价格问题的回归分析_化工数学模型数据回归软件

利用hutool实现邮件发送功能_hutool发送邮件-程序员宅基地

文章浏览阅读7.5k次。如何利用hutool工具包实现邮件发送功能呢?1、首先引入hutool依赖<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.19</version></dependency>2、编写邮件发送工具类package com.pc.c..._hutool发送邮件

docker安装elasticsearch,elasticsearch-head,kibana,ik分词器_docker安装kibana连接elasticsearch并且elasticsearch有密码-程序员宅基地

文章浏览阅读867次,点赞2次,收藏2次。docker安装elasticsearch,elasticsearch-head,kibana,ik分词器安装方式基本有两种,一种是pull的方式,一种是Dockerfile的方式,由于pull的方式pull下来后还需配置许多东西且不便于复用,个人比较喜欢使用Dockerfile的方式所有docker支持的镜像基本都在https://hub.docker.com/docker的官网上能找到合..._docker安装kibana连接elasticsearch并且elasticsearch有密码

随便推点

Python 攻克移动开发失败!_beeware-程序员宅基地

文章浏览阅读1.3w次,点赞57次,收藏92次。整理 | 郑丽媛出品 | CSDN(ID:CSDNnews)近年来,随着机器学习的兴起,有一门编程语言逐渐变得火热——Python。得益于其针对机器学习提供了大量开源框架和第三方模块,内置..._beeware

Swift4.0_Timer 的基本使用_swift timer 暂停-程序员宅基地

文章浏览阅读7.9k次。//// ViewController.swift// Day_10_Timer//// Created by dongqiangfei on 2018/10/15.// Copyright 2018年 飞飞. All rights reserved.//import UIKitclass ViewController: UIViewController { ..._swift timer 暂停

元素三大等待-程序员宅基地

文章浏览阅读986次,点赞2次,收藏2次。1.硬性等待让当前线程暂停执行,应用场景:代码执行速度太快了,但是UI元素没有立马加载出来,造成两者不同步,这时候就可以让代码等待一下,再去执行找元素的动作线程休眠,强制等待 Thread.sleep(long mills)package com.example.demo;import org.junit.jupiter.api.Test;import org.openqa.selenium.By;import org.openqa.selenium.firefox.Firefox.._元素三大等待

Java软件工程师职位分析_java岗位分析-程序员宅基地

文章浏览阅读3k次,点赞4次,收藏14次。Java软件工程师职位分析_java岗位分析

Java:Unreachable code的解决方法_java unreachable code-程序员宅基地

文章浏览阅读2k次。Java:Unreachable code的解决方法_java unreachable code

标签data-*自定义属性值和根据data属性值查找对应标签_如何根据data-*属性获取对应的标签对象-程序员宅基地

文章浏览阅读1w次。1、html中设置标签data-*的值 标题 11111 222222、点击获取当前标签的data-url的值$('dd').on('click', function() { var urlVal = $(this).data('ur_如何根据data-*属性获取对应的标签对象

推荐文章

热门文章

相关标签