实际开发过程中,我们常常需要对接口进行调用来测试接口可用性,同时也需要对接口进行压力测试,来反馈项目的并发量。而这些操作都需要借助第三方工具来实现,今天我们就来聊聊这些测试工具
Jmeter是一款老牌的压测软件,能够帮助我们快速了解接口负载性能。并且jmeter是一款免费、开源的产品,使用直观,易上手
jmeter下载地址
jmeter的安装十分简单,因为其是基于jdk运行的,所以需要提前下载安装jdk,截止目前jmeter的最新版5.5,需要jdk8+。
下载压缩包后,解压,并在安装目录执行启动指令./bin/jmeter
界面如下
开启中文,在设置中点击选择语言,然后选择简体中文
这里我们以创建一个接口测试为例,除了接口测试外,jmeter还能进行jdbc数据库测试、FTP测试、分布式负载测试、JMS测试等,具体可参考官方文档
Jmeter使用手册
1、新增测试计划,并保存
2、测试计划上右键,添加线程组
3、修改线程数,并根据需要调整循环次数,线程数表示同时访问接口的次数,即并发量;循环次数表示会重复调用的次数,一般一次或少量调用并不能很好反馈接口的性能,需要通过多次调用来反馈平均结果
其中Ramp-Up时间表示创建所有线程需要的时间
4、添加HTTP请求取样器,所谓取样器就是我们要测试的接口信息
5、配置取样器信息,因为我们是HTTP请求测试,所以配置的就是我们要进行压测的接口地址,如有参数则可在下方的参数列表中配置
6、在线程组下添加监听器,所谓监听器就是我们压测的结果输出,不同的监听器会输出不同的结果指标
这里我们选择添加上结果树监听器
其次我们再添加上一个汇总报告
7、选择需要测试的取样器,再点击运行按钮进行测试
8、从结果树监听器中我们可以看到请求的结果,当线程数是100时,所有的请求都能成功
9、还可以通过汇总结果来查看测试的汇总数据,包括总调用次数、吞吐量
JMH(Java Microbenchmark Harness),Java微基准测试工具,主要用于方法的基准测试,精度可达到纳秒级,当我们需要对某些方法的性能进行精准测试时,就可以通过JMH进行量化分析
相比于jmeter,JMH在性能消耗上更加节省,更适合针对方法的精准性能测试
为了保证测试的准确性,官方的建议是将需要测试的代码和依赖包打包,然后单独运行测试,但是实际开发中这样的方式比较麻烦,所以我们也可以通过在IDEA中安装JMH插件来达到类似效果,虽然准确性有所下降,但还是在接受范围内
由于需要用到注解,需要打开idea的注解配置
settings -> Build,Executor,Deployment -> complier -> Annotation Processors-> Enable Annotation Processing
JMH是通过注解的方式来声明一些性能测试指标的,常用注解如下所示:
注解 | 说明 |
---|---|
@Warmup(iterations = 1,time = 3) | 预热,先让虚拟机启动起来, 先调用这个测试的方法1次即预热1次,然后等待3秒。JVM中会将执行次数较多的代码编译为本地代码,以提高执行效率。因此预热次数越多,之后的执行效率越高 |
@Fork(5) | 用5个进程去执行程序 |
@BenchmarkMode(Mode.Throughput) | 测试模式,Mode.Throughput表示吞吐量模式,吞吐量表示要测试的接口每秒可以执行多少次,一共有4种模式Throughput: 吞吐量,每秒可执行次数;AverageTime: 每次调用的平均耗时时间;SampleTime: 随机进行采样执行的时间;SingleShotTime: 在每次执行中计算耗时 |
@Measurement(iterations = 1,time = 3) | 这个测试方法要测试多少次,间隔多少秒,一般这个次数应该设置的比较多,默认是5 |
@State(Scope.Thread) | 指定对象作用范围。Scope.Benchmark:所有测试线程共享一个实例,测试有状态实例在多线程共享下的性能; Scope.Group:同一个线程在同一个 group 里共享实例;Scope.Thread:默认的 State,每个测试线程分配一个实例 |
@Threads(4) | 每个进程的测试线程数 |
@OutputTimeUnit(TimeUnit.SECONDS) | 以秒输出统计结果 |
1、JMH已嵌套到jdk9中,如果是jdk9之前,需要单独引入以下依赖
org.openjdk.jmh
jmh-core
1.29
org.openjdk.jmh
jmh-generator-annprocess
1.29
test
3、这里我们举例测试接口、静态方法、非静态方法
准备接口OrderController,注意这里要用@Component("orderController")
声明bean名,用于后续我们在测试类中通过spring容器获取bean
准备一个静态方法
准备一个非静态方法
4、因为我们这里有接口要测试,因此需要读取配置文件,从而获取数据库连接、其他组件的相关配置信息,于是我们添加一个单独配置文件application-jmh.properties
,作为jmh测试使用
注意:该配置文件只能是.properties
的,不能是yml
,否则会读取不到配置文件
5、同时上述我们创建controller时声明了bean名,那么我们还需要创建一个配置类AnnotationConfig
,用来声明bean的扫描范围,并且设置读取的配置文件
可以看到非静态方法类的引入,是通过new的方式创建出来然后声明为bean
6、在测试路径下创建JMH测试类JMHTest
,因为我们需要在测试类中引入bean,直接通过依赖注入的方法是无法引入的,会产生空指针异常。
因此我们需要通过AnnotationConfigApplicationContext
上下文来引入bean,但该类的创建方法中需要声明一个配置类,用该类来声明注入的bean。也就是我们上面创建的AnnotationConfig
。
其方法如下
public JMHTest(){
// 获取bean
annotationConfigApplicationContext = new AnnotationConfigApplicationContext(AnnotationConfig.class);
userController = annotationConfigApplicationContext.getBean("userController",UserController.class);
orderController = annotationConfigApplicationContext.getBean("orderController",OrderController.class);
userUtil = annotationConfigApplicationContext.getBean("userUtil",UserUtil.class);
}
同时使用完成后,我们还需要关闭上下文
@TearDown
public void close(){
// 关闭资源
annotationConfigApplicationContext.close();
}
完整代码如下(这里我们还配置了将结果输出到指定文件jmh-result.json中)
所有文件目录结构如图
7、启动测试,点击main方法运行,注意不要以debug形式启动!!!
8、等待片刻,如下则运行完成了
9、结果分析
最终命名行输出的结果有6列
列名 | 说明 |
---|---|
Benchmark | 测试方法名,其中p0.00、p0.50、p0.99、p1.00等表示0、50、99、100%的请求的测试结果不超过Score值 |
Mode | 测试类型,也就是@BenchmarkMode中选择的类型,分别为thrpt-吞吐量(tps,ops),avgt-每次请求的平均耗时,sample-请求样本数量,这次压测一共发了多少个请求,ss-除去冷启动,一共执行了多少轮 |
Cnt | 执行次数 |
Score | 得分,即结果数据值 |
Error | 误差 |
Units | 单位 |
我们上述输出的结果文件为jmh-result.json
,直接查看是看不懂的。需要将该文件导入下述两个网站进行分析
https://jmh.morethan.io
http://deepoove.com/jmh-visual-chart
如图,接口的测试结果就显而易见了
上述演示源码已上传git,可在如下地址下载
https://gitee.com/wuhanxue/jmh-test
相对大家熟悉的postman软件,apipost作为一款国产测试软件,更加了解国内开发者的需求,支持协同测试、压力测试、全局参数、mock测试、代码生成、笔记等功能。用了Apipost就再也回不去postman了
针对于还未搭建swagger的项目时,使用apipost进行接口文档说明更加方便
Apipost下载
Apipost的使用非常简单,如果已经使用过postman的同学,可以快速上手apipost,各类功能详解可以参考官方使用手册
Apipost使用文档