使用JMeter进行性能测试 —“Java请求”方式

2,730 阅读7分钟

JMeter是Apache组织的开放源代码项目,它是功能和性能测试的工具,100%的用java实现,最新的版本是2.9,大家可以到官网下载源代码和查看相关文档。之前本科的时候,SQA课程作业中我们组使用过2.4版本,这次更新了2.9感觉最直观的就是界面上有了小的更改,增加了清除、启动等按钮。

关于使用JMeter进行JDBC数据库测试、HTTP请求接口测试、结合Badboy录制功能进行网站性能测试等内容,网上的资料比较丰富,这里就暂时不做介绍了。更实用和灵活的场景,是实用我们自己编写的jar包进行测试,这也就是“Java请求”方式的测试。这里主要记录一下我在学习这种测试方式时遇到的一些问题,和总体流程,算作一个记录和小总结。

1. JMeter安装

准确的来说,我认为JMeter是不需要安装的,下载好JMeter Binary版本后,在本地解压缩,进入bin文件夹,执行ApacheJMeter.jar文件即可。这里提供一个观望的2.9版本的下载链接,时间久了可能会失效,这个时候可以进入Apache JMeter项目主页再选择download页面。

img

打开JMeter程序后,我们可以看到JMeter的主界面,是下图的这个样子(2.9版本)。

img

2. 使用JMeter创建测试计划

如果我们希望实用JMeter进行性能测试,则首先需要创建一个测试计划,我们可以对测试计划进行保存,这样当我们下一次需要再次执行这个测试的时候,只需要打开已保存的测试计划文件(.jmx文件)就可以执行了,无需再次创建。

1)点击“测试计划”,在右侧输入框中可以修改测试计划的名称,并添加注释,这里我偷个懒就不改了,使用默认的。

2)为测试计划添加一组Threads,选择线程组。这组Threads就相当于是一组用户,每个显示代表一个用户执行相关操作。

img

  1. 编辑线程组属性。设置响应内容,比较重要的是线程数、ramp-up period和循环次数。这里设置线程数为1、ramp-up period为1和循环次数1,即线程组中只有1个线程,这个线程在计划启动后1秒就开始执行,只执行1次。

img

图上的ramp-up period解释不正确,这个属性表示每个用户(线程)启动的迟延时间。例如,如果你输入Ramp-Up Period 为5秒,JMeter将会在五秒结束前完成启动所有的用户。所以,如果你有五个用户并且Ramp-Up Period为5秒,那么开始用户的延迟就是1秒。(5个用户/5秒=1用户每秒)。如果你设置的Ramp-Up Period为0,则JMeter将会立即启动你所有的用户。

如果勾选了“调度器”,则可以定时启动线程。

img

4)为线程组添加Sampler取样器,取样器表明这组线程执行测试的类型,即发送请求的类型、怎样发送请求的。我们这里选择“Java请求”,表明这组线程是通过某个Java类发送请求的。

img

4)编辑“Java请求”属性。下图这个大家可以发现已经有了Launcher类,和userName、password、authUrl的值了,这是因为:1. 我之前写了满足一定要求的代码,打了jar包,放入了JMeter的lib/ext文件夹下了,所以可以看到Launcher;2. 我在Launcher类中的getDefaultParameters方法中添加了默认的userName、password、authUrl值。这里的“满足一定要求”请继续参阅下文。

img

5)为Java请求添加监听器,选择“聚合报表”和“图形结果”,这样在启动测试后,我们就可以获得测试结果的数据,分别以报表和图形的结果展示。

img
img

6)点击启动(菜单栏中的绿色三角形按钮)。测试完成可以看到测试结果。为了结果好看一点,我把线程数改成了10,循环改成了100 :P

img

img

这里对测试结果中的几个指标进行说明:

样本数目 总共发送到服务器的请求数。
最新样本 代表时间的数字,是服务器响应最后一个请求的时间。
吞吐量 服务器每分钟处理的请求数。
平均值 是总运行时间除以发送到服务器的请求数,即每个请求的平均响应时间。
中间值 是代表时间的数字,有一半的服务器响应时间低于该值而另一半高于该值。
偏离 表示服务器响应时间变化、离散程度测量值的大小,即数据的分布。
90%line 90%的响应时间都比这个时间小
Min 代表时间的数字,是服务器响应的最短时间。
Max 代表时间的数字,是服务器响应的最长时间。
Error% 请求的错误百分比。
KB/sec 是每秒钟请求的字节数。

3. 实现“Java请求”代码

针对"Java请求"类型的测试,需要基于JMeter测试框架编写测试用例。

1)新建一个普通的Java工程

2)添加JMeter的包引用,这些包位于 JMeter安装目录/lib/ext下,一般只需要ApacheJMeter_core.jar和ApacheJMeter_java.jar这两个。

3)新建一个Java Class,如下例中的“Launcher”,并继承“AbstractJavaSamplerClient”。AbstractJavaSamplerClient中默认实现了四个可以覆盖的方法,分别是“getDefaultParameters”,“setupTest”,“runTest”和“teardownTest”方法。

  • getDefaultParameters 方法主要用于设置传入界面的参数;
  • setupTest方法为初始化方法,用于初始化性能测试时的每个线程;
  • runTest方法为性能测试时的线程运行体;
  • teardownTest方法为测试结束方法,用于结束性能测试中的每个线程。

[

复制代码
](javascript:void(0);)

package cn.edu.zju.swift.test;

import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
import org.apache.jmeter.samplers.SampleResult;

import cn.edu.zju.swift.JtangSwiftClient;
import cn.edu.zju.swift.model.result.AccountResult;

public class Launcher extends AbstractJavaSamplerClient{
    
    private JtangSwiftClient client;
    
    @Override
    /**
     * JMeter界面中展示出此方法所设置的默认参数。
     * @return
     */
    public Arguments getDefaultParameters() {
        
        Arguments args = new Arguments();
        
        args.addArgument("authUrl", "http://192.168.3.51:8080/auth/v1.0");
        args.addArgument("userName", "test:tester");
        args.addArgument("password", "testing");
                
        return args;
    }

    /** 
     * 执行runTest()方法前会调用此方法,可放一些初始化代码 
     */ 
    @Override
    public void setupTest(JavaSamplerContext context) {
        
        // 创建SwiftClient
        this.client = new JtangSwiftClient(15000, 15000, 8192, true, false);
    }

    /** 
     * 执行runTest()方法后会调用此方法,可放一些资源释放代码
     */ 
    @Override
    public void teardownTest(JavaSamplerContext context) {
        
        // 关闭连接
        this.client.close();
    }

    @Override
    /**
     * 性能测试时的线程运行体,执行的业务方法放在这里。
     */
    public SampleResult runTest(JavaSamplerContext context) {
        
        // 创建SampleResult对象,用于记录执行结果的状态,并返回
        SampleResult sampleResult = new SampleResult();

        
        // 获取JMeter中输入的用户参数
        String authUrl = context.getParameter("authUrl");
        String userName = context.getParameter("userName");
        String password = context.getParameter("password");
        
        // 开始
        sampleResult.sampleStart();
        
        AccountResult accountResult = client.auth(authUrl, userName, password);

        // 暂停
        // sampleResult.samplePause();
        
        // 重启
        // sampleResult.sampleResume();
        
        // 结束
        sampleResult.sampleEnd();
        
        sampleResult.setSuccessful(accountResult.isSuccess());
        
        // 返回
        return sampleResult;
    }
}

[

复制代码
](javascript:void(0);)

4)代码编写完毕后,把上面的例子打包(使用eclipse右键项目 -> export -> jar,即可)。然后把生成的"swift-random-action-test.jar"文件拷贝到JMeter的安装目录lib\ext下,就可以在上述“2. 使用JMeter创建测试计划”的4)Java请求编辑页面的下拉列表中看到Launcher类了。

这里有两点需要注意

\1. 如果你的jar依赖了其他第三方jar,需要将其一起放到lib/ext下,否则会出现ClassNotFound错误,这个问题也是困扰了我好久的 T^T;

\2. 如果在将jar放入lib/ext后,你还是无法找到你编写的类,且此时你是开着JMeter的,则需要重启一下JMeter。

以上就是使用JMeter的Java请求方式进行一个测试计划构建的全过程了,都是比较基础的方法,如果需要什么额外的功能还可以慢慢学习。虽然自己也有写多线程并发的客户端测试代码,并自己收集response time等,计算TPS,但显然使用JMeter的方式更加方便,因为你只需要按照单线程的方式去实现你的测试业务,也无需添加各种埋点收集数据。

综上,感觉JMeter还是很强大的,最近打算多学习一点,对以后写代码,自我测试性能也是很有帮助的,再配合jProfiler的使用,可以很好的保证Java代码的效率和性能。当然,工具只能“锦上添花”,最根本的还是需要我们自己可以编写出高质量的代码啦 :D