Jmeter添加插件

JMeter插件分類

GUI組件 非GUI組件
ThreadGroup(線程組)
Test Fragment(測試片段)
logic Controller(邏輯控制器)
Config element(配置元件)
Timer(定時器)
pre processor(前置處理器)
post processor(后置處理器)
Sampler(測試抽樣器)
Assertion(斷言)
Listener(監(jiān)聽器)
Function(函數)

JMeter Gui – TestElement約定

在編寫任何JMeter組件時其弊,必須注意某些特定的約定——如果JMeter環(huán)境中正確地運行JMeter組件癣朗,那么它將會運行碍侦。本部分描述了組件的GUI部分必須滿足的約定恨旱。

JMeter中的GUI代碼嚴格地與測試元件代碼(這里指邏輯控制代碼座慰,下同)分離往堡。因此械荷,當編寫一個組件時,將會有一個用于測試元件的類虑灰,另一個用于GUI表示吨瞎。GUI類是無狀態(tài)的,因此它不應該掛在對測試元件的引用上(盡管有例外)穆咐。
GUI元素應該繼承適當的抽象類:

AbstractSamplerGui

AbstractAssertionGui

AbstractConfigGui

AbstractControllerGui

AbstractPostProcessorGui

AbstractPreProcessorGui

AbstractVisualizer

AbstractTimerGui

……

這些抽象類提供了大量的管道工作颤诀,不用擴展,用來代替直接實現接口对湃。

已經繼承了適當的GUI類崖叫,剩下要遵循以下步驟:

  • 實現getResourceLabel()

該方法返回資源的標題/名稱。

  • 創(chuàng)建GUI
    無論使用什么樣式熟尉,都要布局GUI归露。類最終要繼承JPanel洲脂,因此布局必須在的類自己的ContentPane中斤儿。不要通過動作和事件將·GUI元素連接到測試元件類。讓swing的內部模型盡可能多地掛在所有數據上恐锦。

    • 一些標準的GUI內容應該添加到所有JMeter GUI組件中:

      • 調用setBorder(makeBorder())往果。這將給它提供標準的JMeter邊框。

      • 通過makeTitlePanel()添加標題窗格一铅。通常這是添加到GUI中的第一件事陕贮,應該在一個垂直布局方案中完成,或者使用JMeter的VerticalLayout類潘飘。下面是一個示例init()方法:

  • 實現public void configure(TestElement el)

    • 一定調用super.configure(e)肮之,這將填充一些數據掉缺,比如元素的名稱

    • 使用此方法將數據設置為GUI元素。如下例

  • 實現public void modifyTestElement(TestElement e)戈擒,這是將數據從GUI元素移動到TestElement的地方眶明。這是前一種方法的邏輯逆操作

首先調用super.configureTestElement(e),處理一些默認數據筐高;如下圖

  • 實現public TestElement createTestElement()搜囱,該方法應該創(chuàng)建TestElement類的一個新實例,然后將其傳遞modifyTestElement(TestElement)方法

不能保留對測試元件的引用的原因是因為JMeter的測試元件重用了多個GUI類對象的實例柑土。這樣可以節(jié)省很多內存蜀肘。它還使得編寫新組件的GUI部分變得非常容易。您仍然需要與Swing中的布局進行斗爭稽屏,但是不必擔心如何創(chuàng)建正確的事件和從GUI元素中獲取數據放入測試元件中扮宠。JMeter知道什么時候調用自定義配置,以及可以用一種非常簡單的方式來完成它的修改诫欠。

總結:

GUI與測試元件分離:GUI部分通過繼承各種組件GUI抽象類涵卵,測試元件部分通過繼承組件抽象類和實現各種接口方式從而實現不同組件的內部邏輯控制;

GUI與測試元件不分離:與分離方法的區(qū)別在于不單獨實現GUI部分荒叼,在測試元件部分通過實現TestBean接口方法從而實現對GUI界面的配置轿偎。(TestBean是一個空接口:Marker interface to tell JMeter to make a Test Bean Gui for the class)

JMeter插件組件實現

TestElement是所有組件的最基本單元,組件類都是TestElement類的子類
組件的實現需完成兩部分:GUITestElement

GUI部分的實現

繼承并實現對應的抽象類

1.png

邏輯控制實現

Assertion(斷言)組件

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

XPathAssertion
摘自Jmeter源碼

public class XPathAssertion extends AbstractScopedAssertion implements Serializable, Assertion {
 
    @Override
    public AssertionResult getResult(SampleResult response) {
        // no error as default
        AssertionResult result = new AssertionResult(getName());
        result.setFailure(false);
        result.setFailureMessage("");

        byte[] responseData = null;
        Document doc = null;

        try {
            if (isScopeVariable()){
                String inputString=getThreadContext().getVariables().get(getVariableName());
                if (!StringUtils.isEmpty(inputString)) {
                    responseData = inputString.getBytes(StandardCharsets.UTF_8);
                } 
            } else {
                responseData = response.getResponseData();
            }
          .....
    }

Config(配置元件)組件

Config(配置元件)組件相對其他組件比較特殊昆婿,通過繼承ConfigTestElement類或只需要GUI部分的實現即可完成本體任務

public class CSVDataSet extends ConfigTestElement 
    implements TestBean, LoopIterationListener, NoConfigMerge {
    private static final Logger log = LoggerFactory.getLogger(CSVDataSet.class);
}

ThreadGroup(線程組)組件

ThreadGroup(線程組)組件繼承AbstractThreadGroup抽象類,通過重寫各類控制方法來達到控制和協(xié)調各線程(虛擬用戶)的行為蜓斧,線程組是構建一個性能測試模型的最基本組件.

public abstract class AbstractThreadGroup extends AbstractTestElement 
    implements Serializable, Controller, JMeterThreadMonitor, TestCompilerHelper {
...
 /** {@inheritDoc} */
    @Override
    public boolean isDone() {
        return getSamplerController().isDone();
    }

    /** {@inheritDoc} */
    @Override
    public Sampler next() {
        return getSamplerController().next();
    }
    @Override
    public void addTestElement(TestElement child) {
        getSamplerController().addTestElement(child);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final boolean addTestElementOnce(TestElement child){
        if (children.putIfAbsent(child, DUMMY) == null) {
            addTestElement(child);
            return true;
        }
        return false;
    }
...
}

Timer(定時器)組件

Timer(定時器)組件通過繼承AbstractTestElement抽象類仓蛆,實現Timer接口的delay()方法來實現對時間的控制

public class ConstantTimer extends AbstractTestElement implements Timer, Serializable, LoopIterationListener {
   ..... 
   @Override
    public long delay() {
        return delay;
    }
}

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

pre processor(前置處理器)組件

pre processor(前置處理器)組件通過繼承AbstractTestElement抽象類能庆,實現PreProcessor接口的process ()方法控制邏輯

@GUIMenuSortOrder(Integer.MAX_VALUE)
public class BeanShellPreProcessor extends BeanShellTestElement
    implements Cloneable, PreProcessor, TestBean
{
    private static final Logger log = LoggerFactory.getLogger(BeanShellPreProcessor.class);

    private static final long serialVersionUID = 5;

    // can be specified in jmeter.properties
    private static final String INIT_FILE = "beanshell.preprocessor.init"; //$NON-NLS-1$

    @Override
    protected String getInitFileProperty() {
        return INIT_FILE;
    }

    @Override
    public void process(){
        final BeanShellInterpreter bshInterpreter = getBeanShellInterpreter();
        if (bshInterpreter == null) {
            log.error("BeanShell not found");
            return;
        }
        JMeterContext jmctx = JMeterContextService.getContext();
        Sampler sam = jmctx.getCurrentSampler();
        try {
            // Add variables for access to context and variables
            bshInterpreter.set("sampler", sam);//$NON-NLS-1$
            processFileOrScript(bshInterpreter);
        } catch (JMeterException e) {
            if (log.isWarnEnabled()) {
                log.warn("Problem in BeanShell script. {}", e.toString());
            }
        }
    }
    
    @Override
    public Object clone() {
        return super.clone();
    }
}

post processor(后置處理器)組件

post processor(后置處理器)組件通過繼承AbstractTestElement抽象類,實現PostProcessor接口的process ()方法控制邏輯

@GUIMenuSortOrder(Integer.MAX_VALUE)
public class BeanShellPostProcessor extends BeanShellTestElement
    implements Cloneable, PostProcessor, TestBean
{
    private static final Logger log = LoggerFactory.getLogger(BeanShellPostProcessor.class);

    private static final long serialVersionUID = 5;
    
    // can be specified in jmeter.properties
    private static final String INIT_FILE = "beanshell.postprocessor.init"; //$NON-NLS-1$

    @Override
    protected String getInitFileProperty() {
        return INIT_FILE;
    }

    @Override
    public void process() {
        JMeterContext jmctx = JMeterContextService.getContext();

        SampleResult prev = jmctx.getPreviousResult();
        if (prev == null) {
            return; // TODO - should we skip processing here?
        }
        final BeanShellInterpreter bshInterpreter = getBeanShellInterpreter();
        if (bshInterpreter == null) {
            log.error("BeanShell not found");
            return;
        }

        try {
            // Add variables for access to context and variables
            bshInterpreter.set("data", prev.getResponseData());//$NON-NLS-1$
            processFileOrScript(bshInterpreter);
        } catch (JMeterException e) {
            if (log.isWarnEnabled()) {
                log.warn("Problem in BeanShell script: {}", e.toString());
            }
        }
    }
     
    @Override
    public Object clone() {
        return super.clone();
    }
}

Controller(控制器)組件

Controller(控制器)組件通過繼承GenericController類
foreach脚线,重寫isDone搁胆、next、nextIsNull、getIterCount渠旁、reInitialize攀例、initialize、triggerEndOfLoop

@GUIMenuSortOrder(5)
public class ForeachController extends GenericController implements Serializable, IteratingController {
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isDone() {
        if (loopCount >= getEndIndex()) {
            return true;
        }
        JMeterContext context = getThreadContext();
        StringBuilder builder = new StringBuilder(
                getInputVal().length()+getSeparator().length()+3);
        String inputVariable = 
                builder.append(getInputVal())
                .append(getSeparator())
                .append(Integer.toString(loopCount+1)).toString();
        final JMeterVariables variables = context.getVariables();
        final Object currentVariable = variables.getObject(inputVariable);
        if (currentVariable != null) {
            variables.putObject(getReturnVal(), currentVariable);
            if (log.isDebugEnabled()) {
                log.debug("{} : Found in vars:{}, isDone:{}",
                        getName(), inputVariable, Boolean.FALSE);

            }
            return false;
        }
        return super.isDone();
    }

    // Prevent entry if nothing to do
    @Override
    public Sampler next() {
        try {
            if (breakLoop || emptyList()) {
                resetBreakLoop();
                reInitialize();
                resetLoopCount();
                return null;
            }
            return super.next();
        } finally {
            updateIterationIndex(getName(), loopCount);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected Sampler nextIsNull() throws NextIsNullException {
        reInitialize();
        // Conditions to reset the loop count
        if (breakLoop
                || endOfArguments() // no more variables to iterate
                || loopCount >= getEndIndex() // we reached end index
                ) {
            resetBreakLoop();
            resetLoopCount();
            return null;
        }
        return next();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected int getIterCount() {
        return loopCount + 1;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void reInitialize() {
        setFirst(true);
        resetCurrent();
        incrementLoopCount();
        recoverRunningVersion();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void triggerEndOfLoop() {
        super.triggerEndOfLoop();
        resetLoopCount();
    }

    /**
     * Reset loopCount to Start index
     * @see org.apache.jmeter.control.GenericController#initialize()
     */
    @Override
    public void initialize() {
        super.initialize();
        loopCount = getStartIndex();
    }

    @Override
    public void startNextLoop() {
        reInitialize();
    }

    @Override
    public void breakLoop() {
        breakLoop = true;
        setFirst(true);
        resetCurrent();
        resetLoopCount();
        recoverRunningVersion();
    }

    @Override
    public void iterationStart(LoopIterationEvent iterEvent) {
        reInitialize();
        resetLoopCount();
    }
}

Sampler(測試抽樣器)組件

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

@GUIMenuSortOrder(2)
public class DebugSampler extends AbstractSampler implements TestBean {

....
    @Override
    public SampleResult sample(Entry e) {
        SampleResult res = new SampleResult();
        res.setSampleLabel(getName());
        res.sampleStart();
        StringBuilder sb = new StringBuilder(100);
        StringBuilder rd = new StringBuilder(20); // for request Data
        if (isDisplayJMeterVariables()){
            rd.append("JMeterVariables\n");
            sb.append("JMeterVariables:\n");
            formatSet(sb, JMeterContextService.getContext().getVariables().entrySet());
            sb.append("\n");
        }
    }
....
}

Listener(監(jiān)聽器)

直接繼承AbstractTestElement投慈,實現sampleListenerVisualizer等接口方法

@GUIMenuSortOrder(Integer.MAX_VALUE)
public class BeanShellListener extends BeanShellTestElement
    implements Cloneable, SampleListener, TestBean, Visualizer, UnsharedComponent  {
@Override
    protected String getInitFileProperty() {
        return INIT_FILE;
    }

    @Override
    public void sampleOccurred(SampleEvent se) {
        final BeanShellInterpreter bshInterpreter = getBeanShellInterpreter();
        if (bshInterpreter == null) {
            log.error("BeanShell not found");
            return;
        }

        SampleResult samp=se.getResult();
        try {
            bshInterpreter.set("sampleEvent", se);//$NON-NLS-1$
            bshInterpreter.set("sampleResult", samp);//$NON-NLS-1$
            processFileOrScript(bshInterpreter);
        } catch (JMeterException e) {
            if (log.isWarnEnabled()) {
                log.warn("Problem in BeanShell script. {}", e.toString());
            }
        }
    }

    @Override
    public void sampleStarted(SampleEvent e) {
        // NOOP
    }

    @Override
    public void sampleStopped(SampleEvent e) {
        // NOOP
    }

    @Override
    public void add(SampleResult sample) {
        // NOOP
    }

    @Override
    public boolean isStats() { // Needed by Visualizer interface
        return false;
    }

    @Override
    public Object clone() {
        return super.clone();
    }
}

可以從實際用途上將其分為兩大類Report (報告)和Visualizers(監(jiān)視器)承耿。

Report (報告)繼承AbstractListenerElement抽象類,通過實現sampleOccurred(SampleEvent e)方法伪煤,對所有采集事件中所產生的SampleResult進行處理加袋,從而生成報告

Visualizers(監(jiān)視器)主要用于特定的監(jiān)控任務,比如監(jiān)控系統(tǒng)資源利用率的組件抱既,與Report的區(qū)別在于Visualizers必須繼承一個 ResultCollector類职烧,并在收集器中通過開啟額外線程方式完成自定義的數據采集。

Function(函數)

請查閱 Jmeter擴展自定義函數

附錄

JMeter一些GUI類繼承關系



轉載于https://blog.csdn.net/yue530tomtom/article/details/77649872

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末防泵,一起剝皮案震驚了整個濱河市蚀之,隨后出現的幾起案子责球,更是在濱河造成了極大的恐慌指攒,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捕发,死亡現場離奇詭異锁右,居然都是意外死亡失受,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進店門咏瑟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拂到,“玉大人,你說我怎么就攤上這事码泞⌒盅” “怎么了?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵余寥,是天一觀的道長领铐。 經常有香客問我,道長劈狐,這世上最難降的妖魔是什么罐孝? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任呐馆,我火速辦了婚禮肥缔,結果婚禮上,老公的妹妹穿的比我還像新娘汹来。我一直安慰自己续膳,他們只是感情好改艇,可當我...
    茶點故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著坟岔,像睡著了一般谒兄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上社付,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天承疲,我揣著相機與錄音,去河邊找鬼鸥咖。 笑死燕鸽,一個胖子當著我的面吹牛,可吹牛的內容都是我干的啼辣。 我是一名探鬼主播啊研,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼鸥拧!你這毒婦竟也來了党远?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤富弦,失蹤者是張志新(化名)和其女友劉穎沟娱,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體腕柜,經...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡花沉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了媳握。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片碱屁。...
    茶點故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖蛾找,靈堂內的尸體忽然破棺而出娩脾,到底是詐尸還是另有隱情,我是刑警寧澤打毛,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布柿赊,位于F島的核電站,受9級特大地震影響幻枉,放射性物質發(fā)生泄漏碰声。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一熬甫、第九天 我趴在偏房一處隱蔽的房頂上張望胰挑。 院中可真熱鬧,春花似錦、人聲如沸瞻颂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽贡这。三九已至茬末,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間盖矫,已是汗流浹背丽惭。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留辈双,地道東北人吐根。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像辐马,于是被迫代替她去往敵國和親拷橘。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,652評論 2 354

推薦閱讀更多精彩內容

  • 公司最近需要測試后臺性能喜爷,所以學習使用了Jmeter冗疮,在此做記錄,也分享給更多需要的人檩帐。 這篇文章是 JMeter...
    顧顧314閱讀 4,271評論 0 10
  • 主要文體來自 CDNS:https://www.cnblogs.com/ceshisanren/p/5639895...
    Amano閱讀 10,988評論 3 27
  • 在使用Jmeter進行接口的性能測試時术幔,由于Jmeter 是JAVA應用,對于CPU和內存的消耗比較大湃密,所以诅挑,當需...
    燕京博士閱讀 4,166評論 0 16
  • 摘要## JMeter本身提供了插件機制,允許第三方擴展JMeter以支持JMeter不支持的協(xié)議的測試泛源。本文以擴...
    zhulibin2012閱讀 1,393評論 1 2
  • 眼睛純凈拔妥,才能看見美麗的風景;心靈純凈达箍,才能擁有純粹的感情没龙。一個內心純凈的人,必定見過人世的復雜與陰暗缎玫,也經歷過世...
    屈道秋閱讀 268評論 0 0