您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關(guān)JMeter engine中如何配置HashTree,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
大家看到下面是JMeter控制臺配置截圖,是一個標準的菜單形式;菜單形式其實就類似于“樹型”的數(shù)據(jù)結(jié)構(gòu),而HashTree其實就是一個樹型數(shù)據(jù)結(jié)構(gòu)
我們在JMeter控制臺導(dǎo)出的jmx文件,是一個xml結(jié)構(gòu)的數(shù)據(jù),他其實就是由HashTree生成的,后面我們會講到
首先通過HashTree類介紹,它一個集合類;具備Map結(jié)構(gòu)的功能,而且是一種樹型結(jié)構(gòu)
/** * This class is used to create a tree structure of objects. Each element in the * tree is also a key to the next node down in the tree. It provides many ways * to add objects and branches, as well as many ways to retrieve. * <p> * HashTree implements the Map interface for convenience reasons. The main * difference between a Map and a HashTree is that the HashTree organizes the * data into a recursive tree structure, and provides the means to manipulate * that structure. * <p> * Of special interest is the {@link #traverse(HashTreeTraverser)} method, which * provides an expedient way to traverse any HashTree by implementing the * {@link HashTreeTraverser} interface in order to perform some operation on the * tree, or to extract information from the tree. * * @see HashTreeTraverser * @see SearchByClass */ 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(); //創(chuàng)建線程組數(shù)結(jié)構(gòu)的對象groupTree HashTree groupTree = new ListedHashTree(); //表示取樣器中的HTTP請求 HTTPSamplerProxy sampler = new HTTPSamplerProxy(); //創(chuàng)建HTTP請求的數(shù)結(jié)構(gòu)對象samplerTree //調(diào)用put方法相當于在plan(測試計劃)菜單對象下添加group(線程組)子菜單,這樣就形成了一種樹型結(jié)構(gòu) HashTree samplerTree = new ListedHashTree(); samplerTree.put(sampler,new ListedHashTree()) //groupTree樹結(jié)構(gòu)添加子樹samplerTree groupTree.put(group,samplerTree) //tree樹結(jié)構(gòu)為測試計劃對象,添加子樹groupTree,這樣就形成了上圖的層級形式 tree.put(plan, groupTree) //調(diào)用add方法相當于在tree菜單對象下添加同級菜單 tree.add(Object key)
首先在JMeter控制臺所有點擊事件,都會被ActionRouter
中performaAction方法進行監(jiān)聽執(zhí)行,點擊導(dǎo)出按鈕,會進入到如圖方法通過反射由Save類執(zhí)行
在Save類中執(zhí)行doAction主要是獲取到配置的HashTree
當你點擊保存的時候,它會創(chuàng)建一個空文件,此時文件沒有任何內(nèi)容
Save
類的doAction方法最后會調(diào)用backupAndSave(e, subTree, fullSave, updateFile)
這個是來將創(chuàng)建的空文件寫入xml內(nèi)容的
在SaveService
中saveTree方法,其中JMXSAVER
是XStream
對象,對應(yīng)的maven坐標如下
<!-- https://mvnrepository.com/artifact/com.thoughtworks.xstream/xstream --> <dependency> <groupId>com.thoughtworks.xstream</groupId> <artifactId>xstream</artifactId> <version>1.4.15</version> </dependency>
首先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>
先創(chuàng)建一個取樣器,然后寫成HashTree的數(shù)據(jù)結(jié)構(gòu)
public static ThreadGroup threadGroup; //創(chuàng)建一個標準的線程組 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; }
創(chuàng)建一個標準的線程組
public static ThreadGroup threadGroup; //創(chuàng)建一個標準的線程組 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; }
創(chuàng)建一個標準的測試計劃
public static TestPlan testPlan; //創(chuàng)建一個標準的測試計劃 private static void initTestPlan() { TestPlan plan = new TestPlan(); //設(shè)置測試計劃屬性及內(nèi)容,最后都會轉(zhuǎn)為xml標簽的屬性及內(nèi)容 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的配置
//先創(chuàng)建一個測試計劃hashtree對象 HashTree hashTree = new ListedHashTree(); //在創(chuàng)建一個線程組threaddGroupTree對象 HashTree threadGroupTree = new ListedHashTree(); //HttpRequestConfig為HTTP對應(yīng)的請求頭、請求體等信息數(shù)據(jù),傳入httpToHashTree靜態(tài)方法獲取到取樣器的HashTree數(shù)據(jù)結(jié)構(gòu),源碼上圖已分享 HashTree httpConfigTree = XXClass.httpToHashTree(HttpRequestConfig httpRequestData) //threadGroupTree添加子菜單httpConfigTree對象 threadGroupTree.put(group, httpConfigTree); //測試計劃hashTree添加子菜單threadGroupTree對象 hashTree.put(JMeterTestPlanConfigService.testPlan, threadGroupTree);
HashTree寫好后,調(diào)用JMeter原生方法SaveService.saveTree(hashTree,outStream);
生成對應(yīng)的xml
如果直接調(diào)用的話生成的xml格式會形成如下圖所示,而非JMeter原生導(dǎo)出jmx形式,這種文件結(jié)構(gòu)JMeter控制臺讀取會報錯,識別不了
后面閱讀SaveService源碼才明白,生成xml文件之前會先初始化靜態(tài)代碼塊內(nèi)容,初始化屬性
過程中會調(diào)用JMeterUtils
中的findFile方法來尋找saveservice.properties文件
由于SaveService
中都是靜態(tài)方法無法重寫,所以根據(jù)最后調(diào)用JMeterUtils
中的findFile方法來尋找saveservice.properties有兩種解決方案
方案一 :不推薦,在項目根目錄下存放saveservice.properties,這樣findFile方法就能拿到,但是這樣不好,因為maven打包的時候該文件會打不進去,至少我springboot項目是遇到這樣的問題
方案二:推薦,創(chuàng)建一個臨時文件命名為saveservice.properties,然后提前將saveservice.properties配置讀取到臨時文件中,這樣在調(diào)用JMeterUtils
中的findFile方法同樣能夠找到配置,成功解決SaveService
初始化屬性導(dǎo)致的問題,具體代碼如下
private void hashTreeToXML(HashTree hashTree,PressureConfigInfo configInfo){ FileOutputStream outStream = null; File file = new File("temp.jmx"); File tempFile = null; try { //創(chuàng)建一個臨時的saveservice.properties文件 tempFile = new File("saveservice.properties"); InputStream is = JMeterUtil.class.getResource("/jmeter/saveservice.properties").openStream(); //將配置文件寫入臨時文件中 FileUtil.writeFromStream(is,tempFile); outStream = new FileOutputStream(file); //調(diào)用saveTree成功轉(zhuǎn)為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文件結(jié)構(gòu)如下圖,通過JMeter控制臺也能成功打開識別
關(guān)于“JMeter engine中如何配置HashTree”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學(xué)到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。