Java 代碼調用 Jmeter

一、Jmeter的簡介

Jmeter一款開源的壓力測試工具,而這款開源的測試工具是基于Java開發。Jmeter最初的設計是為了web的性能測試。而在后面擴展了很多種類的測試。

Jmeter是基于Java編寫,所以使用時需要安裝jdk

二、Jmeter負載測試和性能測試種類

1.Web - HTTP, HTTPS (Java, NodeJS, PHP, ASP.NET, …)
2.SOAP / REST Webservices
3.FTP
4.Database via JDBC
5.LDAP
6.Message-oriented middleware (MOM) via JMS
7.Mail - SMTP(S), POP3(S) and IMAP(S)
8.Native commands or shell scripts
9.TCP
10.Java Objects

三、Jmeter基本組件簡介

我們這里只講解使用到的一些組件。而其他組件可以到Jmeter的官網了解(https://jmeter.apache.org/),在Jmeter下每個組件都是節點的方式進行配置。如我們在圖形化界面中,都會有一個TestPlan的根節點,其他控件都添加在根節點下。

3.1.TestPlan
測試計劃,每一個測試都為一個測試計劃。

2.ThreadGroup:是一個測試計劃的開始。所有的controller、sampler必須在線程組下。不過有一些特許的控件如Listeners可以直接在TestPlan下。

3.sampler:采樣器,也就是我們各種性能測試和負載測試的收集器。如:http采樣器:HTTPSampler等

4.Controller:主要用于壓力測試邏輯的處理,如我們這里使用了LoopController進行控制線程的循環次數,是永久還是循環壓力測試多次。

四、Jmeter的調用方式

調用Jmeter有5中方式:

五、使用JAVA調用jmeter

一、創建項目

我們這里使用了Ecplise IDE創建Maven項目。

二、導入Jmeter的包

 我們這里演示使用的是http的壓力測試。所以會用到ApacheJMeter_http的包和ApacheJMeter_core的包
  <!--jmeter核心包-->
       <dependency>
            <groupId>org.apache.jmeter</groupId>
            <artifactId>ApacheJMeter_core</artifactId>
            <version>4.0</version>
        </dependency>
  <!--jmeter組件包-->
        <dependency>
            <groupId>org.apache.jmeter</groupId>
            <artifactId>ApacheJMeter_components</artifactId>
            <version>4.0</version>
        </dependency>
  <!--jmeter Http包-->
        <dependency>
            <groupId>org.apache.jmeter</groupId>
            <artifactId>ApacheJMeter_http</artifactId>
            <version>4.0</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

三、演示代碼

package com.study;

import java.io.File;

import org.apache.jmeter.JMeter;
import org.apache.jmeter.control.LoopController;
import org.apache.jmeter.engine.StandardJMeterEngine;
import org.apache.jmeter.protocol.http.control.HeaderManager;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
import org.apache.jmeter.reporters.ResultCollector;
import org.apache.jmeter.reporters.Summariser;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.testelement.TestPlan;
import org.apache.jmeter.threads.ThreadGroup;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.collections.HashTree;

public class TestPlanLauncher {

    public static void main(String[] args) {
        // jemter 引擎
        StandardJMeterEngine standardJMeterEngine = new StandardJMeterEngine();
        // 設置不適用gui的方式調用jmeter
        System.setProperty(JMeter.JMETER_NON_GUI, "true");
        // 設置jmeter.properties文件,我們將jmeter文件存放在resources中,通過classload
        String path = TestPlanLauncher.class.getClassLoader().getResource("jmeter.properties").getPath();
        File jmeterPropertiesFile = new File(path);
        if (jmeterPropertiesFile.exists()) {
            JMeterUtils.loadJMeterProperties(jmeterPropertiesFile.getPath());
            HashTree testPlanTree = new HashTree();
            // 創建測試計劃
            TestPlan testPlan = new TestPlan("Create JMeter Script From Java Code");
            // 創建http請求收集器
            HTTPSamplerProxy examplecomSampler = createHTTPSamplerProxy();
            // 創建循環控制器
            LoopController loopController = createLoopController();
            // 創建線程組
            ThreadGroup threadGroup = createThreadGroup();
            // 線程組設置循環控制
            threadGroup.setSamplerController(loopController);
            // 將測試計劃添加到測試配置樹種
            HashTree threadGroupHashTree = testPlanTree.add(testPlan, threadGroup);
            // 將http請求采樣器添加到線程組下
            threadGroupHashTree.add(examplecomSampler);
            //增加結果收集
            Summariser summer = null;
            String summariserName = JMeterUtils.getPropDefault("summariser.name", "summary");
            if (summariserName.length() > 0) {
                summer = new Summariser(summariserName);
            }
            ResultCollector logger = new ResultCollector(summer);
            testPlanTree.add(testPlanTree.getArray(), logger);
            
            // 配置jmeter
            standardJMeterEngine.configure(testPlanTree);
            // 運行
            standardJMeterEngine.run();
        }
    }

    /**
     * 創建線程組
     * 
     * @return
     */
    public static ThreadGroup createThreadGroup() {
        ThreadGroup threadGroup = new ThreadGroup();
        threadGroup.setName("Example Thread Group");
        threadGroup.setNumThreads(1);
        threadGroup.setRampUp(0);
        threadGroup.setProperty(TestElement.TEST_CLASS, ThreadGroup.class.getName());
        threadGroup.setScheduler(true);
        threadGroup.setDuration(60);
        threadGroup.setDelay(0);
        return threadGroup;
    }

    /**
     * 創建循環控制器
     * 
     * @return
     */
    public static LoopController createLoopController() {
        // Loop Controller
        LoopController loopController = new LoopController();
        loopController.setLoops(-1);
        loopController.setContinueForever(true);
        loopController.setProperty(TestElement.TEST_CLASS, LoopController.class.getName());
        loopController.initialize();
        return loopController;
    }

    /**
     * 創建http采樣器
     * 
     * @return
     */
    public static HTTPSamplerProxy createHTTPSamplerProxy() {
        HeaderManager headerManager = new HeaderManager();
        headerManager.setProperty("Content-Type", "multipart/form-data");
        HTTPSamplerProxy httpSamplerProxy = new HTTPSamplerProxy();
        httpSamplerProxy.setDomain("www.baidu.com");
        httpSamplerProxy.setPort(80);
        httpSamplerProxy.setPath("/");
        httpSamplerProxy.setMethod("GET");
        httpSamplerProxy.setConnectTimeout("5000");
        httpSamplerProxy.setUseKeepAlive(true);
        httpSamplerProxy.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName());
        httpSamplerProxy.setHeaderManager(headerManager);
        return httpSamplerProxy;
    }
}

三、詳講

3.1 Jmeter引擎StandardJMeterEngine

StandardJMeterEngine是Java調用Jmeter的入口。

3.2 Jmeter.properties文件
  • 指定Jmeter.properties文件,Jmeter.properties文件主要用于Jmeter全局基礎配置。我們可以根據自己的需求進行修改配置文件。
    例如我們需要進行分布式壓力測試的情況下,我們就需要在remote_hosts添加遠程的IP。
  • 指定jmeter.properties文件的方式,我們可以通過源碼的分析發現加載配置Jmeter.properties配置文件,先從指定的文件中查找,如果查找不到jmeter.properties文件,會在org/apache/jmeter/jmeter.properties查找查找。也就是說我們可以將配置文件存放在org/apache/jmeter路徑下或者指定配置文件。
    public static void loadJMeterProperties(String file) {
        Properties p = new Properties(System.getProperties());
        InputStream is = null;
        try {
            File f = new File(file);
            is = new FileInputStream(f);
            p.load(is);
        } catch (IOException e) {
            try {
                is = ClassLoader.getSystemResourceAsStream(
                        "org/apache/jmeter/jmeter.properties"); // $NON-NLS-1$
                if (is == null) {
                    throw new RuntimeException("Could not read JMeter properties file:" + file);
                }
                p.load(is);
            } catch (IOException ex) {
                throw new RuntimeException("Could not read JMeter properties file:" + file);
            }
        } finally {
            JOrphanUtils.closeQuietly(is);
        }
        appProperties = p;
    }
3.3 HashTree

我們在使用Jmeter的圖形化界面的時候,我們可以看出所有組件都是添加在TestPlan下。而在使用非圖形化界面的時,我們的StandardJMeterEngine通過configure方法來進行配置我們的TestPlan、ThreadGroup、LoopController等組件,因此需要創建HashTree。

3.4 TestPlan

我們在使用圖形化界面都知道所有組件都是存放在TestPlan中,所以我們需要創建一個TestPlan用于存放組件。

3.5 HTTPSamplerProxy

HTTPSamplerProxy是HTTP采樣器,在Jmeter中提供做了多種采樣器,我們可以根據采樣數據來確定到底使用哪一個采樣器。在壓力測試時,是通過Thread Group來進行創建線程進行壓力測試的。每個線程都需要通過Sampler來確定去并發訪問,因此Sampler是存放在Thread Group下。


image.png
3.6 LoopController

LoopController是一個壓力循環次數的控制器。我們通常會配置ThreadGroup進行使用,例如我們在Thread Group中設置持續5秒,并發量50的情況下,我們會這是LoopController為永久循環。我們需要注意:永久循環的情況下loops應設置為-1.

 loopController.setLoops(-1);
 loopController.setContinueForever(true);

注意:Controller是存放在Thread Group下。

3.7 ThreadGroup

在Jmeter下是通過線程方式去并發訪問,線程管理Jmeter通過ThreadGroup來控制線程的數量和線程的創建、線程持續訪問的時間。

3.8 ResultCollector
  • ResultCollector是一個結果的收集器,ResultController收集請求結果是通過監聽的方式進行收集結果。
  • 通過查看ResultController的源碼發現其實現了SampleListener接口,并且調用sampleOccurred方法處理每個sampler的結果。
    /**
     * When a test result is received, display it and save it.
     *
     * @param event
     *            the sample event that was received
     */
    @Override
    public void sampleOccurred(SampleEvent event) {
        SampleResult result = event.getResult();

        if (isSampleWanted(result.isSuccessful())) {
            sendToVisualizer(result);
            if (out != null && !isResultMarked(result) && !this.isStats) {
                SampleSaveConfiguration config = getSaveConfig();
                result.setSaveConfig(config);
                try {
                    if (config.saveAsXml()) {
                        SaveService.saveSampleResult(event, out);
                    } else { // !saveAsXml
                        String savee = CSVSaveService.resultToDelimitedString(event);
                        out.println(savee);
                    }
                } catch (Exception err) {
                    log.error("Error trying to record a sample", err); // should throw exception back to caller
                }
            }
        }

        if(summariser != null) {
            summariser.sampleOccurred(event);
        }
    }
  • 在ResultController.sampleOccurred方法中我們可以看到summariser不為空的情況下調用summariser的sampleOccurred方法,從summariser.sampleOccurred方法我們可以知道summariser一定是實現了SampleListener接口。
public class Summariser extends AbstractTestElement
    implements Serializable, SampleListener, TestStateListener, NoThreadClone, Remoteable {
  • 在多線程的情況下,Jmeter會對Controller、Sampler等組件為每個線程拷貝一份對象。而對于組件ResultCollector是不拷貝對象。

/**
 * This class handles all saving of samples.
 * The class must be thread-safe because it is shared between threads (NoThreadClone).
 */
public class ResultCollector extends AbstractListenerElement implements SampleListener, Clearable, Serializable,
        TestStateListener, Remoteable, NoThreadClone {

Reference:
https://jmeter.apache.org/api/index.html
https://www.blazemeter.com/blog/5-ways-launch-jmeter-test-without-using-jmeter-gui
https://jmeter.apache.org/usermanual/get-started.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 主要文體來自 CDNS:https://www.cnblogs.com/ceshisanren/p/5639895...
    Amano閱讀 11,070評論 3 27
  • 大學是一個成長的圖標,一步步前進到這里,付出了很多——時間,精力,重要的是青春。我們用一整個青春奮斗一個大學,...
    薄荷微涼々閱讀 321評論 0 0
  • 不要等到明天,明天太遙遠,今天就行動。 須讀:看完該文章你能做什么? NSArray文件讀寫 學習前:你必須會什么...
    liyuhong閱讀 313評論 0 0
  • 最近一直下雨,一下雨地鐵就很擠,濕答答的雨傘把你的褲子弄濕,你卻無處可躲。前面人的長發從你臉上掃過,后面人的書包靠...
    南瓜土豆餅閱讀 138評論 0 3
  • 今晚吃過飯和我爸散步,突然被問道現在最好的朋友是誰?我愣了一下,久久給不出答案。 這個問題的本身是簡單的,可就是找...
    你有什么不會的啊閱讀 415評論 0 0