京东质量社区 Jmeter Sampler (取样器插件开发) 制定自己的 Sampler

taki for 京东 · 2016年03月29日 · 最后由 cc 回复于 2018年03月04日 · 3261 次阅读
本帖已被设为精华帖!

Jmeter 可以帮助我们做性能测试、接口测试,然而 Jmeter 支持常用的 HTTP 等协议,如果某个公司采用自由协议那么 Jmeter 要采用实现【JavaSamplerClient】接口,这种方式当然是比较好的,但是有些东西和 Jmeter 自身的参数化等等功能,不太好结合,有的还有 BUG,当然这个最灵活的,当然也可以采取做一个协议插件,嵌入到 Jmeter 中,那么怎么做呢?

1. 首先第一个做一个测试的 GUI,要实现 AbstractSamplerGui 类做才能被 Jmeter 加载


public class DemoSampleGui extends AbstractSamplerGui implements ItemListener {
    private DemoParamConfigGui demoParamConfigGui;

    public DemoSampleGui() {    //构造方法初始化
          init();
      }
  /**
     * @Descrition初始化
    * */
    private void init() {
        setLayout(new BorderLayout(0, 5));
        setBorder(makeBorder());
        add(makeTitlePanel(), BorderLayout.NORTH);            //设置布局

        demoParamConfigGui = new DemoParamConfigGui();   //这里是另外一个面板类,抽出去了,一会单独说
        add(demoParamConfigGui, BorderLayout.CENTER);
    }
    /**
     * @Descrition清除页面数据信息
    * */
     @Override                           
      public void clearGui() {
        super.clearGui();
        demoParamConfigGui.clear();
    }
 /**
     * @Descrition:配置组装元素信息
    * */
     @Override                           
    public void configure(TestElement element) {
        super.configure(element);
        final MySamplerSamplerBase samplerBase = (MySamplerSamplerBase) element;
        safParamConfigGui.configure(element);
    }

   /**
     * @Descrition:创建新的元素
    * */
    @Override
    public TestElement createTestElement() {
        MySamplerSamplerBase sampler = new MySamplerSamplerBase();
        modifyTestElement(sampler);
        return sampler;
    }
    /**
     * @Descrition:清除旧的组件,从新创建
    * */
    @Override
    public void modifyTestElement(TestElement sampler) {
        sampler.clear();
        safParamConfigGui.modifyTestElement(sampler);
        this.configureTestElement(sampler);
    }
   /**
     * @Descrition:label信息,也就是创建HTTP请求、JAVA请求
    * */
    @Override
    public String getLabelResource() {
        return "mySampler_title"; 
    }
}

Label 那个由于 Jmeter 实现国际化,所以在配置文件里,通过 mySampler_title 去资源文件里面找的,如果我们想添加自己的需要修改 CORE 里面的配置文件,增加自己对应的 UICODE 编码


2.DemoParamConfigGui 类,这个类主要是初始化面板信息,和修改信息用的,我简单列几行代码,下面给最终的截图,这里可以根据自己的要求更改

public class MySamplerParamConfigGui extends JPanel{
    public JTextField interfaceName;
    public JTextField interfaceAddress;         
    public JTextField interfaceGroup;
    public JTextField interfaceVersion;
    public JTextField interfaceMethod;      //定义几个页面输入框,这个根据自身需要开发哈,我这个是简单的例子
 /**
     * @Descrition:初始化面板
    * */
 private void init() {
        setLayout(new BorderLayout(0, 5));
        if (displayName) {
            setBorder(makeBorder());
            add(makeTitlePanel(), BorderLayout.NORTH);
        }
        // MAIN PANEL
        VerticalPanel mainPanel = new VerticalPanel();
        JPanel serverPanel = new HorizontalPanel();
        serverPanel.add(createInterfaceAddressPanel(), BorderLayout.CENTER);
        mainPanel.add(serverPanel);
        mainPanel.add(createInterfaceNamePanel());
        mainPanel.add(getInterfaceGroupPanel());
        mainPanel.add(createInterfaceVersionPanel());
        mainPanel.add(createInterfaceMethodPanel());
        mainPanel.add(createJarFilePathPanel());
        add(mainPanel, BorderLayout.CENTER);
    }

 /**
     * @Descrition:创建文本框信息
    * */
private JPanel createInterfaceMethodPanel() {                              //初始化上面文本对象,这里我列举一个例子,剩下都一下就是信息和布局的区别
        interfaceMethod = new JTextField(15);
        JLabel label = new JLabel("调用方法:"); // $NON-NLS-1$
        label.setLabelFor(interfaceMethod);
        JPanel panel = new JPanel(new BorderLayout(5, 0));
        panel.add(label, BorderLayout.WEST);
        panel.add(interfaceMethod, BorderLayout.CENTER);
        return panel;
    }


3.Sampler 相关的类


public class MySamplerSamplerBase extends AbstractSampler
        implements TestStateListener, TestIterationListener, ThreadListener, Interruptible {
////////////////////// Code ///////////////////////////

    public MySamplerSamplerBase() {
        setArguments(new Arguments());
    }
    public void setInterfaceName(String newInterfaceName) {
        this.setProperty(InterfaceName, newInterfaceName);
    }
    public String getInterfaceAddress() {
        return getPropertyAsString(InterfaceAddress);
    }
    public String getInterfaceName() {
        return getPropertyAsString(InterfaceName);
    }
    public void setInterfaceGroup(String newInterfaceGroup) {
        this.setProperty(InterfaceGroup, newInterfaceGroup, ""); 
    }
    public String getInterfaceGroup() {
        return getPropertyAsString(InterfaceGroup, ""); 
    }
    public String getInterfaceVersion() {
        return getPropertyAsString(InterfaceVersion);
    }
    public String getInterfaceMethod() {
        return getPropertyAsString(InterfaceMethod);
    }                                                                                              //这些都是从界面获取数据

 /**
     * @Descrition:设置参数
    * */
    public void setArguments(Arguments value) {                        //设置和获取参数
        setProperty(new TestElementProperty(ARGUMENTS, value)); 
    }

 /**
     * @Descrition:获取参数
    * */
    public Arguments getArguments() {
        return (Arguments) getProperty(ARGUMENTS).getObjectValue();
    }

/**
     * @Descrition:执行sampler这个非常重要了,是执行sampler的地方
    * */
     @Override
    public SampleResult sample(Entry e) {
        return sample();
    }

  private transient MySamplerAbstractImpl impl;   //sampler执行类的抽象类,
  /**
     * @Descrition:执行sampler
    * */
   public SampleResult sample() {
        SampleResult res = null;
        try {
            if (impl == null) {                                                   //这里面可以做工厂模式,处理不同的协议sampler
                impl = new MySamplerTestSampler(this);
                List  argumentList=getArgumentList();        //获取参数数据,默认的HTTP请求就是在这里组装带参数的URL,传入不同的client的
                res = impl.sample(argumentList);
                res.setSampleLabel(getName());
            }
            return res;
        } catch (Exception e) {
            return errorResult(e, new SampleResult());
        }
    }
  /**
   * @Descrition: 这里面组装表格传过来的数据,传LIST过去 ,这里可以任意自己处理数据格式    
      * */
    public List getArgumentList() {
        List<MySamplerArgument> list = new ArrayList();
        PropertyIterator iter = getArguments().iterator();
        while (iter.hasNext()) {
            MySamplerArgument item = null;
            Object objectValue = iter.next().getObjectValue();
            try {
                item = (MySamplerArgument) objectValue;
                list.add(item);
            } catch (ClassCastException e) {
                log.warn("Unexpected argument type: " + objectValue.getClass().getName());
                item = new MySamplerArgument((Argument) objectValue);
            }
        }
        return list;
    }
}

*4.具体 sampler 执行类,具体的协议请求发起客户端要你自己定义了,集成到 Jar 包里就行,所有的类编写完成打 JAR 包扔到 Jmeter/lib/ext 下
*


public class MySamplerTestSampler extends MySamplerAbstractImpl {

@Override
    protected SampleResult sample(List list) {  //因为我定时的是list类型 所以这里面是list
        SampleResult res = new SampleResult();
      SampleResult res = new SampleResult();
        System.out.println("list:"+list.toString());
        try {
            String interfaceAddress = getInterfaceAddress();
            System.out.println("interfaceAddress:"+interfaceAddress);
            String interfaceName = getInterfaceName();
            res.setSamplerData("interfaceAddress:"+interfaceAddress+"interfaceName:"+interfaceName);
            res.sampleStart();
            res.setResponseData("list参数:"+list.toString(),"UTF-8");
        } catch (RuntimeException e) {
            res.setResponseCode("500");
            res.setSuccessful(false);
            res.setResponseMessage(e.toString());
            e.printStackTrace();
            return res;
        }  catch (Exception e) {
            res.setResponseCode("500");
            res.setSuccessful(false);
            res.setResponseMessage(e.toString());
            e.printStackTrace();
            return res;
        } finally {
            res.sampleEnd();
        }
        return res;
  }
}

5.演示




共收到 10 条回复 时间 点赞

过几天我自己实践下, 遇到不明白再来请教下.

正是我想要的,话说这些自定义插件开发在官网有示例不

taki #5 · 2016年03月30日 Author

#2 楼 @rennixing 官网好像是没有的,我不太确定

—— 来自 TesterHome 官方 安卓客户端

我想问下,多个接口有耦合关系的情况下,怎么弄?比如登陆成功后返回给 token...然后把 token 传给其他接口等,类似的

taki #6 · 2016年04月05日 Author

#4 楼 @lose 和 http 的一样

你好,请问那个键值对形式的输入参数界面,是用 jmeter 哪个方法实现的?或者能不能麻烦给一下 configGUI 类的代码? 多谢🙏

taki #8 · 2017年06月27日 Author
小郑 回复

说实话我忘记了····

taki 回复

configGUI 的代码还在吗?

注册中心要卸载 xml 中,把地址写在前台。直接传入到 xml 的 zookeeper 配置那里吗?

能加下您 qq 或微信吗,我有问题想问下?

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册