jmeter写插件

来源:互联网 发布:高斯金字塔 python 编辑:程序博客网 时间:2024/06/05 10:36

JMeter Gui – TestElement约定

在编写任何JMeter组件时,必须注意某些特定的约定——如果JMeter环境中正确地运行JMeter组件,那么它将会运行。本部分描述了组件的GUI部分必须满足的约定。
JMeter中的GUI代码严格地与测试元件代码(这里指逻辑控制代码,下同)分离。因此,当编写一个组件时,将会有一个用于测试元件的类,另一个用于GUI表示。GUI类是无状态的,因此它不应该挂在对测试元件的引用上(尽管有例外)。

GUI元素应该继承适当的抽象类:

  • AbstractSamplerGui
  • AbstractAssertionGui
  • AbstractConfigGui
  • AbstractControllerGui
  • AbstractPostProcessorGui
  • AbstractPreProcessorGui
  • AbstractVisualizer
  • AbstractTimerGui
  • ……

这些抽象类提供了大量的管道工作,不用扩展,用来代替直接实现接口。

已经继承了适当的GUI类,剩下要遵循以下步骤:
1、实现getResourceLabel()
该方法返回资源的标题/名称。
2、创建GUI。无论使用什么样式,都要布局GUI。类最终要继承JPanel,因此布局必须在的类自己的ContentPane中。不要通过动作和事件将·GUI元素连接到测试元件类。让swing的内部模型尽可能多地挂在所有数据上。
(1)一些标准的GUI内容应该添加到所有JMeter GUI组件中:
a、调用setBorder(makeBorder())。这将给它提供标准的JMeter边框。
b、通过makeTitlePanel()添加标题窗格。通常这是添加到GUI中的第一件事,应该在一个垂直布局方案中完成,或者使用JMeter的VerticalLayout类。下面是一个示例init()方法:

private void init() {    setLayout(new BorderLayout());    setBorder(makeBorder());    Box box = Box.createVerticalBox();    box.add(makeTitlePanel());    box.add(makeSourcePanel());    add(box,BorderLayout.NORTH);    add(makeParameterPanel(),BorderLayout.CENTER);}

3、实现public void configure(TestElement el)
(1)一定调用super.configure(e),这将填充一些数据,比如元素的名称
(2)使用此方法将数据设置为GUI元素。例子

public void configure(TestElement el) {    super.configure(el);    useHeaders.setSelected(el.getPropertyAsBoolean(RegexExtractor.USEHEADERS));    useBody.setSelected(!el.getPropertyAsBoolean(RegexExtractor.USEHEADERS));    regexField.setText(el.getPropertyAsString(RegexExtractor.REGEX));    templateField.setText(el.getPropertyAsString(RegexExtractor.TEMPLATE));    defaultField.setText(el.getPropertyAsString(RegexExtractor.DEFAULT));    matchNumberField.setText(el.getPropertyAsString(RegexExtractor.MATCH_NUM));    refNameField.setText(el.getPropertyAsString(RegexExtractor.REFNAME));}

(3)实现public void modifyTestElement(TestElement e),这是将数据从GUI元素移动到TestElement的地方。这是前一种方法的逻辑逆操作
a、调用super.configureTestElement(e),处理一些默认数据
b、例子

public void modifyTestElement(TestElement e) {    super.configureTestElement(e);    e.setProperty(new BooleanProperty(            RegexExtractor.USEHEADERS,            useHeaders.isSelected()));    e.setProperty(RegexExtractor.MATCH_NUMBER,            matchNumberField.getText());    if (e instanceof RegexExtractor) {        RegexExtractor regex = (RegexExtractor)e;        regex.setRefName(refNameField.getText());        regex.setRegex(regexField.getText());        regex.setTemplate(templateField.getText());        regex.setDefaultValue(defaultField.getText());    }}

(4)实现public TestElement createTestElement(),该方法应该创建TestElement类的一个新实例,然后将其传递modifyTestElement(TestElement)方法

public TestElement createTestElement() {    RegexExtractor extractor = new RegexExtractor();    modifyTestElement(extractor);    return extractor;}

不能保留对测试元件的引用的原因是因为JMeter的测试元件重用了多个GUI类对象的实例。这样可以节省很多内存。它还使得编写新组件的GUI部分变得非常容易。您仍然需要与Swing中的布局进行斗争,但是不必担心如何创建正确的事件和从GUI元素中获取数据放入测试元件中。JMeter知道什么时候调用自定义配置,以及可以用一种非常简单的方式来完成它的修改。

总结:

GUI与测试元件分离:GUI部分通过继承各种组件GUI抽象类,测试元件部分通过继承组件抽象类和实现各种接口方式从而实现不同组件的内部逻辑控制;
GUI与测试元件不分离:与分离方法的区别在于不单独实现GUI部分,在测试元件部分通过实现TestBean接口方法从而实现对GUI界面的配置。(TestBean是一个空接口:Marker interface to tell JMeter to make a Test Bean Gui for the class)

jmeter插件分类

GUI的组件主要包括10大组件

  • ThreadGroup(线程组)
  • Test Fragment(测试片段)
  • logic Controller(逻辑控制器)
  • Config element(配置元件)
  • Timer(定时器)
  • pre processor(前置处理器)
  • post processor(后置处理器)
  • Sampler(测试抽样器)
  • Assertion(断言)
  • Listener(监听器);

非GUI组件

  • Function(函数)

JMeter插件式组件实现

TestElement是所有组件的最基本单元,组件类都是TestElement类的子类
依据上面介绍,组件的实现分两部分:GUI和TestElement

GUI部分的实现

继承实现对应的抽象类

抽象类 继承的类 对应组件备注 AbstractAssertionGui AbstractScopedJMeterGuiComponent 断言 AbstractConfigGui AbstractJMeterGuiComponent 配置 AbstractControllerGui AbstractJMeterGuiComponent 控制 AbstractPostProcessorGui AbstractScopedJMeterGuiComponent 后置处理器 AbstractPreProcessorGui AbstractJMeterGuiComponent 前置处理器 AbstractSamplerGui AbstractJMeterGuiComponent 取样器 AbstractThreadGroupGui AbstractJMeterGuiComponent 线程组 AbstractTimerGui AbstractJMeterGuiComponent 定时器 AbstractListenerGui AbstractJMeterGuiComponent 监听器 AbstractVisualizer AbstractListenerGui 组件依赖 AbstractScopedJMeterGuiComponent AbstractJMeterGuiComponent 组件依赖 AbstractJMeterGuiComponent JPanel 组件依赖 AbstractFunction Function 组件依赖 AbstractJMeterGuiComponent JPanel 组件依赖

逻辑控制实现

Assertion(断言)组件

Assertion(断言)组件通过继承AbstractTestElement抽象类(或者AbstractTestElement子类),实现Assertion接口的getResult(SampleResult result)方法对结果内容进行判断,从而实现断言方法,用于对Sampler组件所产生的抽样采集结果内容进行断言。

比如:

public class XMLSchemaAssertion extends AbstractTestElement implements Serializable, Assertion {    ……    @Override    public AssertionResult getResult(SampleResult response) {        AssertionResult result = new AssertionResult(getName());        ……        return result;    }    ……}

再比如:

public abstract class AbstractScopedTestElement extends AbstractTestElement {...}public abstract class AbstractScopedAssertion extends AbstractScopedTestElement{...}public class DurationAssertion extends AbstractScopedAssertion implements Serializable, Assertion {    public static final String DURATION_KEY = "DurationAssertion.duration";     @Override    public AssertionResult getResult(SampleResult response) {        ……        return result;    }    private long getAllowedDuration() {        return getPropertyAsLong(DURATION_KEY);    }    public void setAllowedDuration(long duration) {        setProperty(DURATION_KEY, duration);    }}

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抽象类,通过重写各类控制方法来达到控制和协调各线程(虚拟用户)的行为,线程组是构建一个性能测试模型的最基本组件。

public class ThreadGroupTest extends AbstractThreadGroup {    private static final long serialVersionUID = 1L;    @Override    public void threadFinished(JMeterThread arg0) {}    @Override    public int numberOfActiveThreads() {return 0;}    @Override    public void start(int arg0, ListenerNotifier arg1, ListedHashTree arg2, StandardJMeterEngine arg3) {}    @Override    public void stop() {}    @Override    public boolean stopThread(String arg0, boolean arg1) {return false;}    @Override    public void tellThreadsToStop() {}    @Override    public boolean verifyThreadsStopped() {return false;}    @Override    public void waitThreadsStopped() {}}

Timer(定时器)组件

Timer(定时器)组件通过继承AbstractTestElement抽象类,实现Timer接口的delay()方法来实现对时间的控制

public class TimerTest extends AbstractTestElement implements Timer{    private static final long serialVersionUID = 1L;    @Override    public long delay() {        return 0;    }}

控制线程延时,即用来模仿思考时间(ThinkTime)或键盘时间(KeyTime);

ctronlThread

控制线程行为,如SyncTimer(同步计时器),就是内部利用CyclicBarrier来控制阻塞和释放全部运行线程的逻辑行为,从而达到“集合点”的目的。

public class SyncTimer extends AbstractTestElement implements Timer, Serializable, TestBean, TestStateListener, ThreadListener {    private static final Logger log = LoggerFactory.getLogger(SyncTimer.class);    private static class BarrierWrapper implements Cloneable {        private CyclicBarrier barrier;        public BarrierWrapper() {            this.barrier = null;        }        public BarrierWrapper(int parties) {            this.barrier = new CyclicBarrier(parties);        }        public synchronized void setup(int parties) {            if(this.barrier== null) {                this.barrier = new CyclicBarrier(parties);            }        }        public int await() throws InterruptedException, BrokenBarrierException{            return barrier.await();        }        public int await(long timeout, TimeUnit timeUnit) throws InterruptedException, BrokenBarrierException, TimeoutException {            return barrier.await(timeout, timeUnit);        }        public void reset() {            barrier.reset();        }        @Override        protected Object clone()  {            BarrierWrapper barrierWrapper=  null;            try {                barrierWrapper = (BarrierWrapper) super.clone();                barrierWrapper.barrier = this.barrier;            } catch (CloneNotSupportedException e) {            }            return barrierWrapper;        }    }    ……    public void threadStarted() {        if(getGroupSize() == 0) {            int numThreadsInGroup = JMeterContextService.getContext().getThreadGroup().getNumThreads();            // Unique Barrier creation ensured by synchronized setup            this.barrier.setup(numThreadsInGroup);        }    }    ……}


这里写图片描述

pre processor(前置处理器)组件

pre processor(前置处理器)组件通过继承AbstractTestElement抽象类,实现PreProcessor接口的process ()方法控制逻辑

比如:BeanShellPreProcessor

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();    }}

作用:对线程上下文中的当前Sampler和前一个SampleResult进行识别和判断。

post processor(后置处理器)组件

post processor(后置处理器)组件通过继承AbstractTestElement抽象类,实现PostProcessor接口的process ()方法控制逻辑

public abstract class AbstractScopedTestElement extends AbstractTestElement {……}public class RegexExtractor extends AbstractScopedTestElement implements PostProcessor, Serializable {    ……  @Override  public void process() {}  ……}

作用:对线程上下文中的前一个SampleResult进行识别和判断。

Controller(控制器)组件

Controller(控制器)组件通过继承GenericController类
比如foreach,重写isDone、next、nextIsNull、getIterCount、reInitialize、initialize、triggerEndOfLoop

public class ForeachController extends GenericController implements Serializable {    public ForeachController() {}    ……    @Override    public boolean isDone() {}    @Override    public Sampler next() {}        @Override    protected Sampler nextIsNull() throws NextIsNullException {}    @Override    protected int getIterCount() {return loopCount+1;}    @Override    protected void reInitialize() {}    @Override    public void triggerEndOfLoop() {}    @Override    public void initialize() {}}

Sampler(测试抽样器)组件

Sampler(测试抽样器)组件继承AbstractSampler抽象类,通过重写SampleResult sample(Entry e)方法,实现测试过程以及测试结果的采集功能。

public class DebugSampler extends AbstractSampler implements TestBean {    ……    @Override    public SampleResult sample(Entry e) {}    ……}

Listener(监听器)

直接继承AbstractTestElement,实现sampleListener或Visualizer等接口方法

public class Summariser extends AbstractTestElement    implements Serializable, SampleListener, TestStateListener, NoThreadClone, Remoteable {    ……    @Override    @SuppressWarnings("SynchronizeOnNonFinalField")    public void sampleOccurred(SampleEvent e) {        SampleResult s = e.getResult();        if(IGNORE_TC_GENERATED_SAMPLERESULT && TransactionController.isFromTransactionController(s)) {            return;        }        long now = System.currentTimeMillis() / 1000;// in seconds        SummariserRunningSample myDelta = null;        SummariserRunningSample myTotal = null;        boolean reportNow = false;        synchronized (myTotals) {            if (s != null) {                myTotals.delta.addSample(s);            }            if ((now > myTotals.last + INTERVAL_WINDOW) && (now % INTERVAL <= INTERVAL_WINDOW)) {                reportNow = true;                // copy the data to minimise the synch time                myDelta = new SummariserRunningSample(myTotals.delta);                myTotals.moveDelta();                myTotal = new SummariserRunningSample(myTotals.total);                myTotals.last = now; // stop double-reporting            }        }        if (reportNow) {            formatAndWriteToLog(myName, myDelta, "+");            // Only if we have updated them            if (myTotal != null && myDelta != null &&myTotal.getNumSamples() != myDelta.getNumSamples()) { // NOSONAR                formatAndWriteToLog(myName, myTotal, "=");            }        }    }    ……    }

可以从实际用途上将其分为两大类Report (报告)和Visualizers(监视器)。
Report (报告)继承AbstractListenerElement抽象类,通过实现sampleOccurred(SampleEvent e)方法,对所有采集事件中所产生的SampleResult进行处理,从而生成报告;

public class ResultCollector extends AbstractListenerElement implements SampleListener, Clearable, Serializable,        TestStateListener, Remoteable, NoThreadClone {    ……    @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);        }    }    ……}

Visualizers(监视器)主要用于特定的监控任务,比如监控系统资源利用率的组件,与Report的区别在于Visualizers必须继承一个 ResultCollector类,并在收集器中通过开启额外线程方式完成自定义的数据采集。

public class ResultCollector extends AbstractListenerElement implements SampleListener, Clearable, Serializable, TestStateListener, Remoteable, NoThreadClone {……}

比如标准插件中自定义一个JMXMonCollector

public class CorrectedResultCollector extends ResultCollector {}public class JMXMonCollector extends CorrectedResultCollector implements Runnable, JMXMonSampleGenerator {……}

注意:对于一个需要配置的组件类则需要实现ConfigMergabilityIndicator接口的public boolean applies(ConfigTestElement configElement)方法,用来指明哪些Config组件可以用来对其进行配置

这里参考DebugSampler的源代码如下:

public class DebugSampler extends AbstractSampler implements TestBean {    ……    private static final Set<String> APPLIABLE_CONFIG_CLASSES = new HashSet<>(            Arrays.asList("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);    }    ……}

以上代码指明SimpleConfigGui配置元件可以对DebugSampler组件进行配置。

函数

Function(函数)是非GUI组件,这类组件的实现比较简单,而且功能比较单一,只需要继承相应的抽象类即可~

写一个求字符长度的函数:StrLen

public class StrLen extends AbstractFunction {    private static final List<String> desc = new LinkedList<String>();    private static final String KEY = "__strLen";    static {        desc.add("String to measure length");        desc.add("Name of variable in which to store the result (optional)");    }    private Object[] values;    public StrLen() {    }    @Override    public synchronized String execute(SampleResult previousResult, Sampler currentSampler)            throws InvalidVariableException {        JMeterVariables vars = getVariables();        Integer len = ((CompoundVariable) values[0]).execute().length();        if (vars != null && values.length > 1) {            String varName = ((CompoundVariable) values[1]).execute().trim();            vars.put(varName, len.toString());        }        return len.toString();    }    @Override    public synchronized void setParameters(Collection<CompoundVariable> parameters) throws InvalidVariableException {        checkMinParameterCount(parameters, 1);        values = parameters.toArray();    }    @Override    public String getReferenceKey() {        return KEY;    }    public List<String> getArgumentDesc() {        return desc;    }}

附录

jmeter一些GUI类继承关系

GUI类 继承的类 ResultActionGui AbstractPostProcessorGui ResultSaverGui AbstractListenerGui SummariserGui AbstractListenerGui TestBeanGUI AbstractJMeterGuiComponent ThreadGroupGui AbstractThreadGroupGui SetupThreadGroupGui ThreadGroupGui PostThreadGroupGui ThreadGroupGui WorkBenchGui AbstractJMeterGuiComponent AssertionGui AbstractAssertionGui BeanShellAssertionGui AbstractAssertionGui urationAssertionGui AbstractAssertionGui HTMLAssertionGui AbstractAssertionGui MD5HexAssertionGUI AbstractAssertionGui SizeAssertionGui AbstractAssertionGui SMIMEAssertionGui AbstractAssertionGui XMLAssertionGui AbstractAssertionGui XMLSchemaAssertionGUI AbstractAssertionGui XPathAssertionGui AbstractAssertionGui CriticalSectionControllerGui AbstractControllerGui IncludeControllerGui AbstractControllerGui InterleaveControlGui AbstractControllerGui ModuleControllerGui AbstractControllerGui OnceOnlyControllerGui AbstractControllerGui RandomControlGui AbstractControllerGui RandomOrderControllerGui LogicControllerGui SwitchControllerGui AbstractControllerGui ThroughputControllerGui AbstractControllerGui HtmlExtractorGui AbstractPostProcessorGui RegexExtractorGui AbstractPostProcessorGui XPathExtractorGui AbstractPostProcessorGui JSONPostProcessorGui AbstractPostProcessorGui CounterConfigGui AbstractConfigGui SampleTimeoutGui AbstractPreProcessorGui UserParametersGui AbstractPreProcessorGui TestActionGui AbstractSamplerGui AbstractRandomTimerGui AbstractTimerGui ConstantTimerGui AbstractTimerGui GaussianRandomTimerGui AbstractRandomTimerGui PoissonRandomTimerGui AbstractRandomTimerGui UniformRandomTimerGui AbstractRandomTimerGui AbstractAssertionGui AbstractScopedJMeterGuiComponent AbstractConfigGui AbstractJMeterGuiComponent LoginConfigGui AbstractConfigGui ObsoleteGui AbstractJMeterGuiComponent SimpleConfigGui AbstractConfigGui AbstractControllerGui AbstractJMeterGuiComponent LogicControllerGui AbstractControllerGui RunTimeGui AbstractControllerGui TestFragmentControllerGui AbstractControllerGui TestPlanGui AbstractJMeterGuiComponent TransactionControllerGui AbstractControllerGui WhileControllerGui AbstractControllerGui WorkBenchGui AbstractJMeterGuiComponent FunctionHelper JDialog AbstractJMeterGuiComponent JPanel AbstractScopedJMeterGuiComponent AbstractJMeterGuiComponent AbstractPostProcessorGui AbstractScopedJMeterGuiComponent AbstractPreProcessorGui AbstractJMeterGuiComponent ResultActionGui AbstractPostProcessorGui ResultSaverGui AbstractListenerGui SummariserGui AbstractListenerGui AbstractSamplerGui AbstractJMeterGuiComponent TestBeanGUI AbstractJMeterGuiComponent AbstractThreadGroupGui AbstractJMeterGuiComponent PostThreadGroupGui ThreadGroupGui SetupThreadGroupGui ThreadGroupGui ThreadGroupGui AbstractThreadGroupGui AbstractTimerGui AbstractJMeterGuiComponent AbstractListenerGui AbstractJMeterGuiComponent AbstractVisualizer AbstractListenerGui


原文连接 http://blog.csdn.net/yue530tomtom/article/details/77649872