1. 程式人生 > >【轉】如何為Apache JMeter開發插件(一)

【轉】如何為Apache JMeter開發插件(一)

選擇 ref 測試結果 沒有 通過 pri for entry state

本文轉載於http://blog.csdn.net/column/details/12925.html,作者:xreztento

作者寫的很精華,我打算在此系列操作一遍後,加多點截圖,便於更多人更快上手插件開發

為什麽選擇使用JMeter

當被問到這個問題的時候,也許你會在腦海裏產生很多的理由,比如:

  • Apache基金會下的開源項目,沒有版權問題;
  • 為數不多的還在持續更新的開源性能自動化測試工具;
  • 支持協議豐富,是商用測試工具最佳替代品;
  • 有專門的插件項目做支撐,使得你在實踐中有更多的選擇,比如http://jmeter-plugins.org/就提供了很多優秀的插件為你在使用JMeter執行測試時,可以選擇更多的組件來制定測試計劃,完成測試過程,監控測試數據。

而我的回答是:

關鍵在於不要簡單地把JMeter理解為一個單純的性能測試工具,而應該意識到它還是一個優秀的框架,這甚至成為我選擇它的一個最根本理由,在這裏所有的組件都可以通過自由編寫插件的方式進行添加和完善,對於一個測試工程師來說為JMeter編寫插件式組件其樂無窮!

JMeter基本組件類型及實現方法

對於JMeter的基本組件,我們可以將其簡單的劃分為兩大類:

  • 一類是具備GUI的組件,即可以通過JMeter圖形管理控制器在測試計劃Tree中進行添加的組件,主要包括ThreadGroup(線程組)、Config(配置元件)、Timer(定時器)、Modifier(前置處理器)、Extractor(後置處理器)、Controller(邏輯控制器)、Sampler(測試抽樣器)、Assertion(斷言)和Listener(監聽器);
  • 另一類是非GUI組件,這類組件典型的代表是Function(函數)和某些子測試抽樣器,如JavaSamplerClient。

對於組件一般有兩種實現方法:

  1. GUI與邏輯控制分離:GUI部分通過繼承各種組件GUI抽象類,邏輯控制部分通過繼承組件邏輯抽象類和實現各種接口方式從而實現不同組件的內部邏輯控制;
  2. GUI與邏輯控制不分離:與分離方法的區別在於不單獨實現GUI部分,在邏輯控制部分通過實現TestBean接口方法從而實現對GUI界面的配置。

JMeter插件式組件實現細節概述

TestElement是所有組件的最基本單元,組件類都是TestElement類的子類,JMeter定義了上一章節所介紹的幾種組件模型,並對其規範了各自所需發揮的作用。

(1)GUI部分的實現
GUI部分的實現我們可以在JMeter實現主類org.apache.jmeter.JMeter中發現端倪,該類實際實現了JMeterPlugin接口中的getIconMappings()方法來映射組件所對應的GUI圖標,並為映射關系定義了一個二維數組,如下代碼:

private static final String[][] DEFAULT_ICONS = {
        { "org.apache.jmeter.control.gui.TestPlanGui", "org/apache/jmeter/images/beaker.gif" },
        { "org.apache.jmeter.timers.gui.AbstractTimerGui", "org/apache/jmeter/images/timer.gif" },
        { "org.apache.jmeter.threads.gui.ThreadGroupGui", "org/apache/jmeter/images/thread.gif" },
        { "org.apache.jmeter.visualizers.gui.AbstractListenerGui", "org/apache/jmeter/images/meter.png" },
        { "org.apache.jmeter.config.gui.AbstractConfigGui", "org/apache/jmeter/images/testtubes.png" },
        { "org.apache.jmeter.processor.gui.AbstractPreProcessorGui", "org/apache/jmeter/images/leafnode.gif"},
        { "org.apache.jmeter.processor.gui.AbstractPostProcessorGui", "org/apache/jmeter/images/leafnodeflip.gif"},
        { "org.apache.jmeter.control.gui.AbstractControllerGui", "org/apache/jmeter/images/knob.gif" },
        { "org.apache.jmeter.control.gui.WorkBenchGui", "org/apache/jmeter/images/clipboard.gif" },
        { "org.apache.jmeter.samplers.gui.AbstractSamplerGui", "org/apache/jmeter/images/pipet.png" },
        { "org.apache.jmeter.assertions.gui.AbstractAssertionGui", "org/apache/jmeter/images/question.gif"}
};

可以看到只要是插件類的GUI部分繼承了以上數組中的GUI類,JMeter框架便會自動將其映射為所對應的組件類型和圖標。

(2)邏輯控制部分的實現細節,我們根據組件類別進行一一介紹:

技術分享ThreadGroup(線程組)組件

ThreadGroup(線程組)組件繼承AbstractThreadGroup抽象類,通過重寫各類控制方法,如void scheduleThread(JMeterThread thread) 、stopThread(String threadName, boolean now) 、threadFinished(JMeterThread thread)等,來達到控制和協調各線程(虛擬用戶)的行為,線程組是構建一個性能測試模型的最基本組件。


技術分享Config(配置元件)組件

Config(配置元件)組件相對其他組件比較特殊,通過繼承ConfigTestElement類或只需要GUI部分的實現即可完成本體任務,而對於一個需要配置的組件類則需要實現ConfigMergabilityIndicator接口的public boolean applies(ConfigTestElement configElement)方法,用來指明哪些Config組件可以用來對其進行配置,這裏參考TCPSampler的源代碼如下:

private static final Set<String> APPLIABLE_CONFIG_CLASSES = new HashSet<String>(
            Arrays.asList(new String[]{
                    "org.apache.jmeter.config.gui.LoginConfigGui",
                    "org.apache.jmeter.protocol.tcp.config.gui.TCPConfigGui",
                    "org.apache.jmeter.config.gui.SimpleConfigGui"}));

    @Override
    public boolean applies(ConfigTestElement configElement) {
        String guiClass = configElement.getProperty(TestElement.GUI_CLASS).getStringValue();
        return APPLIABLE_CONFIG_CLASSES.contains(guiClass);
}

以上代碼指明LoginConfigGui、SimpleConfigGui和TCPConfigGui這三個配置元件可以對TCPSampler組件進行配置。


技術分享Timer(定時器)組件

Timer(定時器)組件通過繼承AbstractTestElement抽象類,實現Timer接口的delay()方法來實現對時間的控制,主要的控制內容如下:

  • 控制線程延時,即用來模仿思考時間(ThinkTime)或鍵盤時間(KeyTime);
  • 控制線程行為,如SyncTimer(同步計時器),就是內部利用CyclicBarrier來控制阻塞和釋放全部運行線程的邏輯行為,從而達到“集合點”的目的。

技術分享Modifier(前置處理器)組件

Modifier(前置處理器)組件通過繼承AbstractTestElement抽象類,實現PreProcessor接口的process ()方法控制邏輯,常常需要對線程上下文中的當前Sampler和前一個SampleResult進行識別和判斷,以做出正確的處理,一般的行為是通過取出SampleResult的某些值或直接在當前Sampler啟動sample方法之前對其某些屬性進行修飾。


技術分享Extractor(後置處理器)組件

Extractor(後置處理器)組件通過繼承AbstractTestElement抽象類,實現PostProcessor接口的process ()方法控制邏輯,常常需要對線程上下文中的前一個SampleResult進行識別和判斷,以做出正確的處理。


技術分享Controller(控制器)組件

Controller(控制器)組件通過繼承GenericController類,通過重寫Sampler next()、void setDone(boolean done)、int getIterCount()、void reInitialize()等方法來控制Sampler的測試行為。


技術分享Sampler(測試抽樣器)組件

Sampler(測試抽樣器)組件繼承AbstractSampler抽象類,通過重寫SampleResult sample(Entry e)方法,實現測試過程以及測試結果的采集功能。


技術分享Assertion(斷言)組件

Assertion(斷言)組件通過繼承AbstractTestElement抽象類,實現Assertion接口的getResult(SampleResult result)方法對結果內容進行判斷,從而實現斷言方法,用於對Sampler組件所產生的抽樣采集結果內容進行斷言。


技術分享Listener(監聽器)主要有兩種方案:

  • 直接繼承AbstractTestElement,實現sampleListener或Visualizer等接口方法
  • 實現ResultCollector和Runnable等接口方法

我們可以從實際用途上將其分為兩大類Report (報告)和Vizualizers(監視器)。
Report (報告)繼承AbstractListenerElement抽象類,通過實現sampleOccurred(SampleEvent e)方法,對所有采集事件中所產生的SampleResult進行處理,從而生成報告;
Vizualizers(監視器)主要用於特定的監控任務,比如監控系統資源利用率的組件,與Report的區別在於Vizualizers必須繼承一個 ResultCollector類,並在收集器中通過開啟額外線程方式完成自定義的數據采集。


上面還介紹了諸如Function(函數)這一類非GUI組件,這類組件的實現比較簡單,而且功能比較單一,只需要繼承相應的抽象類。

(3)一些TestElement需要實現的主要接口說明

為了實現更多的特性,組件在必要時還需要實現一些主要的接口和方法,下面舉例說明:

NoThreadClone接口:
This class is not cloned per thread, so this is shared,可以理解為一旦實現了NoThreadClone接口,這個TestElement便不會在線程組下的每個線程中創建,而是一個全局化的組件,因此,無法使用getThreadContext()方法。反之,我們可以發現JMeter實際是通過TestElement的clone()方法為線程組下的每個線程拷貝創建屬於各自的線程上下文內的TestElement,A new instance is created for each thread group, and the clone() method is then called to create copies for each thread in a thread group.如果想要對某些共享資源進行同步操作,需要參考如下方法:

private transient Object lock = new Object();//鎖對象不需要進行序列化,因為分布式在不同主機內存中的鎖對象不必保持一致
@Override
public Object clone() {
    Clazz clazz = (Clazz) super.clone();
    clazz.lock = lock; //保證所有克隆對象共享同一個鎖對象
    return clazz;
}

註:這是種顯式的共享對象方法,由於Java在克隆類對象時,默認是一種“淺克隆”方式,因此,不顯式的共享上述鎖對象,該鎖對象也是默認共享的。

LoopIterationListener接口:
將通過實現 iterationStart(LoopIterationEvent event)方法,控制對每次發生叠代事件時所需要實現的邏輯。

Serializable接口:
為了實現在分布式測試模型中保持一些配置和對象的一致性,就需要實現Serializable接口,通過序列化方式保持不同主機對象屬性的一致性。

TestStateListener接口:
將通過實現testStarted(String string)和testEnded(String string)方法,控制對測試狀態變化事件時所需要實現的邏輯。

另外,在實際插件的編寫過程中還會包括如Remoteable、Interruptible、ThreadListener等接口的應用,會在後面的具體章節進行詳細介紹和應用。

組件即插件,只需一步插入JMeter框架

將編寫好的插件式組件插入JMeter框架非常簡單,只需要將組件整體打包為jar包,並將其拷貝到$JMETER_HOME/ lib/ext路徑下即可使用!

【轉】如何為Apache JMeter開發插件(一)