Java 代碼調(diào)用 Jmeter

一、Jmeter的簡介

Jmeter一款開源的壓力測試工具幕帆,而這款開源的測試工具是基于Java開發(fā)眯搭。Jmeter最初的設(shè)計(jì)是為了web的性能測試。而在后面擴(kuò)展了很多種類的測試恭金。

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

二褂策、Jmeter負(fù)載測試和性能測試種類

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的官網(wǎng)了解(https://jmeter.apache.org/)斤寂,在Jmeter下每個(gè)組件都是節(jié)點(diǎn)的方式進(jìn)行配置耿焊。如我們在圖形化界面中,都會有一個(gè)TestPlan的根節(jié)點(diǎn)扬蕊,其他控件都添加在根節(jié)點(diǎn)下搀别。

3.1.TestPlan
測試計(jì)劃,每一個(gè)測試都為一個(gè)測試計(jì)劃尾抑。

2.ThreadGroup:是一個(gè)測試計(jì)劃的開始歇父。所有的controller蒂培、sampler必須在線程組下。不過有一些特許的控件如Listeners可以直接在TestPlan下榜苫。

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

4.Controller:主要用于壓力測試邏輯的處理垂睬,如我們這里使用了LoopController進(jìn)行控制線程的循環(huán)次數(shù)媳荒,是永久還是循環(huán)壓力測試多次。

四驹饺、Jmeter的調(diào)用方式

調(diào)用Jmeter有5中方式:

五、使用JAVA調(diào)用jmeter

一赏壹、創(chuàng)建項(xiàng)目

我們這里使用了Ecplise IDE創(chuàng)建Maven項(xiàng)目鱼炒。

二、導(dǎo)入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();
        // 設(shè)置不適用gui的方式調(diào)用jmeter
        System.setProperty(JMeter.JMETER_NON_GUI, "true");
        // 設(shè)置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();
            // 創(chuàng)建測試計(jì)劃
            TestPlan testPlan = new TestPlan("Create JMeter Script From Java Code");
            // 創(chuàng)建http請求收集器
            HTTPSamplerProxy examplecomSampler = createHTTPSamplerProxy();
            // 創(chuàng)建循環(huán)控制器
            LoopController loopController = createLoopController();
            // 創(chuàng)建線程組
            ThreadGroup threadGroup = createThreadGroup();
            // 線程組設(shè)置循環(huán)控制
            threadGroup.setSamplerController(loopController);
            // 將測試計(jì)劃添加到測試配置樹種
            HashTree threadGroupHashTree = testPlanTree.add(testPlan, threadGroup);
            // 將http請求采樣器添加到線程組下
            threadGroupHashTree.add(examplecomSampler);
            //增加結(jié)果收集
            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);
            // 運(yùn)行
            standardJMeterEngine.run();
        }
    }

    /**
     * 創(chuàng)建線程組
     * 
     * @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;
    }

    /**
     * 創(chuàng)建循環(huán)控制器
     * 
     * @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;
    }

    /**
     * 創(chuàng)建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調(diào)用Jmeter的入口。

3.2 Jmeter.properties文件
  • 指定Jmeter.properties文件稍坯,Jmeter.properties文件主要用于Jmeter全局基礎(chǔ)配置酬荞。我們可以根據(jù)自己的需求進(jìn)行修改配置文件。
    例如我們需要進(jìn)行分布式壓力測試的情況下劣光,我們就需要在remote_hosts添加遠(yuǎn)程的IP袜蚕。
  • 指定jmeter.properties文件的方式糟把,我們可以通過源碼的分析發(fā)現(xiàn)加載配置Jmeter.properties配置文件绢涡,先從指定的文件中查找,如果查找不到j(luò)meter.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的圖形化界面的時(shí)候缠犀,我們可以看出所有組件都是添加在TestPlan下数苫。而在使用非圖形化界面的時(shí),我們的StandardJMeterEngine通過configure方法來進(jìn)行配置我們的TestPlan辨液、ThreadGroup虐急、LoopController等組件,因此需要創(chuàng)建HashTree滔迈。

3.4 TestPlan

我們在使用圖形化界面都知道所有組件都是存放在TestPlan中止吁,所以我們需要創(chuàng)建一個(gè)TestPlan用于存放組件被辑。

3.5 HTTPSamplerProxy

HTTPSamplerProxy是HTTP采樣器,在Jmeter中提供做了多種采樣器敬惦,我們可以根據(jù)采樣數(shù)據(jù)來確定到底使用哪一個(gè)采樣器盼理。在壓力測試時(shí),是通過Thread Group來進(jìn)行創(chuàng)建線程進(jìn)行壓力測試的俄删。每個(gè)線程都需要通過Sampler來確定去并發(fā)訪問宏怔,因此Sampler是存放在Thread Group下。


image.png
3.6 LoopController

LoopController是一個(gè)壓力循環(huán)次數(shù)的控制器畴椰。我們通常會配置ThreadGroup進(jìn)行使用臊诊,例如我們在Thread Group中設(shè)置持續(xù)5秒,并發(fā)量50的情況下斜脂,我們會這是LoopController為永久循環(huán)妨猩。我們需要注意:永久循環(huán)的情況下loops應(yīng)設(shè)置為-1.

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

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

3.7 ThreadGroup

在Jmeter下是通過線程方式去并發(fā)訪問秽褒,線程管理Jmeter通過ThreadGroup來控制線程的數(shù)量和線程的創(chuàng)建壶硅、線程持續(xù)訪問的時(shí)間。

3.8 ResultCollector
  • ResultCollector是一個(gè)結(jié)果的收集器销斟,ResultController收集請求結(jié)果是通過監(jiān)聽的方式進(jìn)行收集結(jié)果庐椒。
  • 通過查看ResultController的源碼發(fā)現(xiàn)其實(shí)現(xiàn)了SampleListener接口,并且調(diào)用sampleOccurred方法處理每個(gè)sampler的結(jié)果蚂踊。
    /**
     * 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不為空的情況下調(diào)用summariser的sampleOccurred方法约谈,從summariser.sampleOccurred方法我們可以知道summariser一定是實(shí)現(xiàn)了SampleListener接口。
public class Summariser extends AbstractTestElement
    implements Serializable, SampleListener, TestStateListener, NoThreadClone, Remoteable {
  • 在多線程的情況下犁钟,Jmeter會對Controller棱诱、Sampler等組件為每個(gè)線程拷貝一份對象。而對于組件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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末迈勋,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子醋粟,更是在濱河造成了極大的恐慌靡菇,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,294評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件米愿,死亡現(xiàn)場離奇詭異厦凤,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)育苟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,493評論 3 385
  • 文/潘曉璐 我一進(jìn)店門较鼓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人违柏,你說我怎么就攤上這事博烂⊥夭福” “怎么了?”我有些...
    開封第一講書人閱讀 157,790評論 0 348
  • 文/不壞的土叔 我叫張陵脖母,是天一觀的道長士鸥。 經(jīng)常有香客問我,道長谆级,這世上最難降的妖魔是什么烤礁? 我笑而不...
    開封第一講書人閱讀 56,595評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮肥照,結(jié)果婚禮上脚仔,老公的妹妹穿的比我還像新娘。我一直安慰自己舆绎,他們只是感情好鲤脏,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,718評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著吕朵,像睡著了一般猎醇。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上努溃,一...
    開封第一講書人閱讀 49,906評論 1 290
  • 那天硫嘶,我揣著相機(jī)與錄音,去河邊找鬼梧税。 笑死沦疾,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的第队。 我是一名探鬼主播哮塞,決...
    沈念sama閱讀 39,053評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼碌上,長吁一口氣:“原來是場噩夢啊……” “哼薪贫!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起澎媒,我...
    開封第一講書人閱讀 37,797評論 0 268
  • 序言:老撾萬榮一對情侶失蹤晾蜘,失蹤者是張志新(化名)和其女友劉穎邻眷,沒想到半個(gè)月后眠屎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體剔交,經(jīng)...
    沈念sama閱讀 44,250評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,570評論 2 327
  • 正文 我和宋清朗相戀三年改衩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了岖常。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,711評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡葫督,死狀恐怖竭鞍,靈堂內(nèi)的尸體忽然破棺而出板惑,到底是詐尸還是另有隱情,我是刑警寧澤偎快,帶...
    沈念sama閱讀 34,388評論 4 332
  • 正文 年R本政府宣布冯乘,位于F島的核電站,受9級特大地震影響晒夹,放射性物質(zhì)發(fā)生泄漏裆馒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,018評論 3 316
  • 文/蒙蒙 一丐怯、第九天 我趴在偏房一處隱蔽的房頂上張望喷好。 院中可真熱鬧,春花似錦读跷、人聲如沸梗搅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,796評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽无切。三九已至,卻和暖如春丐枉,著一層夾襖步出監(jiān)牢的瞬間订雾,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,023評論 1 266
  • 我被黑心中介騙來泰國打工矛洞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留洼哎,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,461評論 2 360
  • 正文 我出身青樓沼本,卻偏偏與公主長得像噩峦,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子抽兆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,595評論 2 350

推薦閱讀更多精彩內(nèi)容

  • 主要文體來自 CDNS:https://www.cnblogs.com/ceshisanren/p/5639895...
    Amano閱讀 10,978評論 3 27
  • 大學(xué)是一個(gè)成長的圖標(biāo)辫红,一步步前進(jìn)到這里凭涂,付出了很多——時(shí)間,精力贴妻,重要的是青春切油。我們用一整個(gè)青春奮斗一個(gè)大學(xué),...
    薄荷微涼々閱讀 303評論 0 0
  • 不要等到明天名惩,明天太遙遠(yuǎn)澎胡,今天就行動。 須讀:看完該文章你能做什么? NSArray文件讀寫 學(xué)習(xí)前:你必須會什么...
    liyuhong閱讀 293評論 0 0
  • 最近一直下雨攻谁,一下雨地鐵就很擠稚伍,濕答答的雨傘把你的褲子弄濕,你卻無處可躲戚宦。前面人的長發(fā)從你臉上掃過个曙,后面人的書包靠...
    南瓜土豆餅閱讀 129評論 0 3
  • 今晚吃過飯和我爸散步困檩,突然被問道現(xiàn)在最好的朋友是誰?我愣了一下那槽,久久給不出答案悼沿。 這個(gè)問題的本身是簡單的,可就是找...
    你有什么不會的啊閱讀 397評論 0 0