文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

一文搞懂JMeter engine中HashTree的配置问题

2024-04-02 19:55

关注

一、前言

在这里插入图片描述

我们在JMeter控制台导出的jmx文件,是一个xml结构的数据,他其实就是由HashTree生成的,后面我们会讲到

在这里插入图片描述 

二、HashTree的用法

首先通过HashTree类介绍,它一个集合类;具备Map结构的功能,而且是一种树型结构



public class HashTree implements Serializable, Map<Object, HashTree>, Cloneable {
}

JMeter常用的HashTree方法(以下图配置为例)

在这里插入图片描述


//ListedHashTree是HashTree的继承类,可以保证HashTree的顺序性
HashTree tree = new ListedHashTree();
//TestPlan对象,测试计划
TestPlan plan = new TestPlan();
//ThreadGroup对象,线程组
ThreadGroup group = new ThreadGroup();
//创建线程组数结构的对象groupTree
HashTree groupTree = new ListedHashTree();
//表示取样器中的HTTP请求
HTTPSamplerProxy sampler = new HTTPSamplerProxy();
//创建HTTP请求的数结构对象samplerTree
//调用put方法相当于在plan(测试计划)菜单对象下添加group(线程组)子菜单,这样就形成了一种树型结构
HashTree samplerTree = new ListedHashTree();
samplerTree.put(sampler,new ListedHashTree())
//groupTree树结构添加子树samplerTree
groupTree.put(group,samplerTree)
//tree树结构为测试计划对象,添加子树groupTree,这样就形成了上图的层级形式
tree.put(plan, groupTree)
//调用add方法相当于在tree菜单对象下添加同级菜单
tree.add(Object key)

三、JMeter源码导出jmx脚本文件介绍

首先在JMeter控制台所有点击事件,都会被ActionRouter中performaAction方法进行监听执行,点击导出按钮,会进入到如图方法通过反射由Save类执行

在这里插入图片描述

在Save类中执行doAction主要是获取到配置的HashTree

在这里插入图片描述

当你点击保存的时候,它会创建一个空文件,此时文件没有任何内容

在这里插入图片描述Save

类的doAction方法最后会调用backupAndSave(e, subTree, fullSave, updateFile)这个是来将创建的空文件写入xml内容的

在这里插入图片描述

SaveService中saveTree方法,其中JMXSAVERXStream对象,对应的maven坐标如下


<!-- https://mvnrepository.com/artifact/com.thoughtworks.xstream/xstream -->
<dependency>
    <groupId>com.thoughtworks.xstream</groupId>
    <artifactId>xstream</artifactId>
    <version>1.4.15</version>
</dependency>

在这里插入图片描述

四、自定义HashTree生成JMeter脚本

首先maven引入以下几个坐标<jmeter.version>5.3</jmeter.version>


        <dependency>
            <groupId>org.apache.jmeter</groupId>
            <artifactId>ApacheJMeter_http</artifactId>
            <version>${jmeter.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.logging.log4j</groupId>
                    <artifactId>log4j-slf4j-impl</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.jmeter</groupId>
            <artifactId>ApacheJMeter_functions</artifactId>
            <version>${jmeter.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.jmeter</groupId>
            <artifactId>ApacheJMeter_jdbc</artifactId>
            <version>${jmeter.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.jmeter</groupId>
            <artifactId>ApacheJMeter_tcp</artifactId>
            <version>${jmeter.version}</version>
        </dependency>

先创建一个取样器,然后写成HashTree的数据结构


public static ThreadGroup threadGroup;
//创建一个标准的线程组
private static void initThreadGroup(){
    LoopController loopController = new LoopController();
    loopController.setName("LoopController");
    loopController.setProperty(TestElement.TEST_CLASS, LoopController.class.getName());
    loopController.setProperty(TestElement.GUI_CLASS, JMeterUtil.readSaveProperties("LoopControlPanel"));
    loopController.setEnabled(true);
    loopController.setLoops(1);
    ThreadGroup group = new ThreadGroup();
    group.setEnabled(true);
    group.setName("ThreadGroup");
    group.setProperty(TestElement.TEST_CLASS, JMeterUtil.readSaveProperties("ThreadGroup"));
    group.setProperty(TestElement.GUI_CLASS, JMeterUtil.readSaveProperties("ThreadGroupGui"));
    group.setProperty(ThreadGroup.ON_SAMPLE_ERROR,"continue");
    group.setProperty(ThreadGroup.IS_SAME_USER_ON_NEXT_ITERATION,true);
    group.setProperty(TestElement.COMMENTS,"");
    group.setNumThreads(1);
    group.setRampUp(1);
    group.setDelay(0);
    group.setDuration(0);
    group.setProperty(ThreadGroup.ON_SAMPLE_ERROR, ThreadGroup.ON_SAMPLE_ERROR_CONTINUE);
    group.setScheduler(false);
    group.setSamplerController(loopController);
    threadGroup = group;
}

创建一个标准的线程组


public static ThreadGroup threadGroup;
//创建一个标准的线程组
private static void initThreadGroup(){
    LoopController loopController = new LoopController();
    loopController.setName("LoopController");
    loopController.setProperty(TestElement.TEST_CLASS, LoopController.class.getName());
    loopController.setProperty(TestElement.GUI_CLASS, JMeterUtil.readSaveProperties("LoopControlPanel"));
    loopController.setEnabled(true);
    loopController.setLoops(1);
    ThreadGroup group = new ThreadGroup();
    group.setEnabled(true);
    group.setName("ThreadGroup");
    group.setProperty(TestElement.TEST_CLASS, JMeterUtil.readSaveProperties("ThreadGroup"));
    group.setProperty(TestElement.GUI_CLASS, JMeterUtil.readSaveProperties("ThreadGroupGui"));
    group.setProperty(ThreadGroup.ON_SAMPLE_ERROR,"continue");
    group.setProperty(ThreadGroup.IS_SAME_USER_ON_NEXT_ITERATION,true);
    group.setProperty(TestElement.COMMENTS,"");
    group.setNumThreads(1);
    group.setRampUp(1);
    group.setDelay(0);
    group.setDuration(0);
    group.setProperty(ThreadGroup.ON_SAMPLE_ERROR, ThreadGroup.ON_SAMPLE_ERROR_CONTINUE);
    group.setScheduler(false);
    group.setSamplerController(loopController);
    threadGroup = group;
}

创建一个标准的测试计划


public static TestPlan testPlan;
//创建一个标准的测试计划
private static void initTestPlan() {
    TestPlan plan = new TestPlan();
    //设置测试计划属性及内容,最后都会转为xml标签的属性及内容
    plan.setProperty(TestElement.NAME, "测试计划");
    plan.setProperty(TestElement.TEST_CLASS, JMeterUtil.readSaveProperties("TestPlan"));
    plan.setProperty(TestElement.GUI_CLASS, JMeterUtil.readSaveProperties("TestPlanGui"));
    plan.setEnabled(true);
    plan.setComment("");
    plan.setFunctionalMode(false);
    plan.setTearDownOnShutdown(true);
    plan.setSerialized(false);
    plan.setProperty("TestPlan.user_define_classpath","");
    plan.setProperty("TestPlan.user_defined_variables","");
    plan.setUserDefinedVariables(new Arguments());
    testPlan = plan;
}

开始封装成一个HashTree的配置


//先创建一个测试计划hashtree对象
HashTree hashTree = new ListedHashTree();
//在创建一个线程组threaddGroupTree对象
HashTree threadGroupTree = new ListedHashTree();
//HttpRequestConfig为HTTP对应的请求头、请求体等信息数据,传入httpToHashTree静态方法获取到取样器的HashTree数据结构,源码上图已分享
HashTree httpConfigTree = XXClass.httpToHashTree(HttpRequestConfig httpRequestData)
//threadGroupTree添加子菜单httpConfigTree对象
threadGroupTree.put(group, httpConfigTree);
//测试计划hashTree添加子菜单threadGroupTree对象
hashTree.put(JMeterTestPlanConfigService.testPlan, threadGroupTree);

HashTree写好后,调用JMeter原生方法SaveService.saveTree(hashTree,outStream);生成对应的xml

如果直接调用的话生成的xml格式会形成如下图所示,而非JMeter原生导出jmx形式,这种文件结构JMeter控制台读取会报错,识别不了

在这里插入图片描述

在这里插入图片描述

后面阅读SaveService源码才明白,生成xml文件之前会先初始化静态代码块内容,初始化属性

在这里插入图片描述
在这里插入图片描述

过程中会调用JMeterUtils中的findFile方法来寻找saveservice.properties文件

在这里插入图片描述

由于SaveService 中都是静态方法无法重写,所以根据最后调用JMeterUtils中的findFile方法来寻找saveservice.properties有两种解决方案

方案一 :不推荐,在项目根目录下存放saveservice.properties,这样findFile方法就能拿到,但是这样不好,因为maven打包的时候该文件会打不进去,至少我springboot项目是遇到这样的问题

方案二:推荐,创建一个临时文件命名为saveservice.properties,然后提前将saveservice.properties配置读取到临时文件中,这样在调用JMeterUtils中的findFile方法同样能够找到配置,成功解决SaveService初始化属性导致的问题,具体代码如下


private void hashTreeToXML(HashTree hashTree,PressureConfigInfo configInfo){
    FileOutputStream outStream = null;
    File file = new File("temp.jmx");
    File tempFile = null;
    try {
    	//创建一个临时的saveservice.properties文件
        tempFile = new File("saveservice.properties");
        InputStream is = JMeterUtil.class.getResource("/jmeter/saveservice.properties").openStream();
        //将配置文件写入临时文件中
        FileUtil.writeFromStream(is,tempFile);
        outStream = new FileOutputStream(file);
        //调用saveTree成功转为xml
        SaveService.saveTree(hashTree,outStream);
        String xmlContent = FileUtil.readUtf8String(file);
        configInfo.setFile(xmlContent.getBytes());
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        try {
            FileUtils.forceDelete(file);
            FileUtils.forceDelete(tempFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

最后生成的xml文件结构如下图,通过JMeter控制台也能成功打开识别

在这里插入图片描述

到此这篇关于一文搞懂JMeter engine中HashTree的配置问题的文章就介绍到这了,更多相关JMeter engine中HashTree配置内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯