美文网首页
Jmeter添加插件

Jmeter添加插件

作者: 明燕南飞 | 来源:发表于2019-03-06 11:23 被阅读0次

JMeter插件分类

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

JMeter Gui – TestElement约定

在编写任何JMeter组件时,必须注意某些特定的约定——如果JMeter环境中正确地运行JMeter组件,那么它将会运行。本部分描述了组件的GUI部分必须满足的约定。

JMeter中的GUI代码严格地与测试元件代码(这里指逻辑控制代码,下同)分离。因此,当编写一个组件时,将会有一个用于测试元件的类,另一个用于GUI表示。GUI类是无状态的,因此它不应该挂在对测试元件的引用上(尽管有例外)。
GUI元素应该继承适当的抽象类:

AbstractSamplerGui

AbstractAssertionGui

AbstractConfigGui

AbstractControllerGui

AbstractPostProcessorGui

AbstractPreProcessorGui

AbstractVisualizer

AbstractTimerGui

……

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

已经继承了适当的GUI类,剩下要遵循以下步骤:

  • 实现getResourceLabel()

该方法返回资源的标题/名称。

  • 创建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(),该方法应该创建TestElement类的一个新实例,然后将其传递modifyTestElement(TestElement)方法

不能保留对测试元件的引用的原因是因为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插件组件实现

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

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(监听器)

直接继承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(监视器)。

Report (报告)继承AbstractListenerElement抽象类,通过实现sampleOccurred(SampleEvent e)方法,对所有采集事件中所产生的SampleResult进行处理,从而生成报告

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

Function(函数)

请查阅 Jmeter扩展自定义函数

附录

JMeter一些GUI类继承关系



转载于https://blog.csdn.net/yue530tomtom/article/details/77649872

相关文章

网友评论

      本文标题:Jmeter添加插件

      本文链接:https://www.haomeiwen.com/subject/ifhtpqtx.html