🎉 🎂 🍰 TesterHome 创立 6 周年纪念日 🍰 🎂 🎉

性能测试工具 使用 JunitPerf 进行性能测试介绍

simonpatrick · 2018年07月24日 · 最后由 apollo0687 回复于 2018年08月12日 · 2269 次阅读
本帖已被设为精华帖!

使用JunitPerf进行性能测试

以下简单介绍一下如何使用JunitPerf进行性能测试,JunitPerf是基于JUnit4的一个单元性能测试插件,对于会远程调用API测试比较合适,如果想要比较nanosecond 延迟的则需要使用JMH.
使用JunitPerf 测试一些SDK的性能,个人觉得还是不错,而且比JMeter使用起来会简单一些,不需要写JMeter 插件.

JunitPerf 依赖声明

此例子假设使用MAVEN管理项目,所以在POM文件中添加:

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>com.github.noconnor</groupId>
<artifactId>junitperf</artifactId>
<version>1.9.1</version>
</dependency>

构建压力测试类

假设你想衡量DemoPerfService 类中的getServiceId方法:

public class DemoPerfService {

public String getServiceId(String userId){

return UUID.randomUUID().toString();
}
}

那么你可以构建如下的测试类:

public class DemoServiceTest {
@Rule
public JUnitPerfRule perfTestRule = new JUnitPerfRule();
DemoPerfService demoPerfService;
@Before
public void setupService(){
this.demoPerfService = new DemoPerfService();
}
@Test
@JUnitPerfTest(threads = 50,durationMs = 1200,warmUpMs = 100,maxExecutionsPerSecond = 110)
public void getServiceId_withoutTestRequirement() {

String result =demoPerfService.getServiceId("userid");
System.out.println(result);
Assert.assertNotNull(result);
}

直接运行就可以进行压力测试,默认的测试报告可以在build/reports 目录下获取:

以下是对于测试类的几点说明:

Item 定义说明 Default值或说明
@Rule 申明为JUnit 的Rule类
JUnitPerfRule JUnitPerf 测试规则类
@JunitPerfTest 声明为性能测试方法
threads 测试使用的线程数
durationMs 测试持续时间
warmUpMs 测试热身时间 热身时间的测试数据不会计算进最后的测试结果
maxExecutionsPerSecond 方法执行的上限 RateLimiter,控制TPS上限

对自己的测试设置期望值

使用@JUnitPerfTestRequirement 可以给性能测试设置期望值,这个annotation的属性有:

属性 定义
percentits 设置例如90%/95%/50% 响应时间的期望
executionsPerSec 期望每秒执行测试(TPS)
allowedErrorPercentage 允许错误比例
minLatency 期望最小延时,如果实际最小延时超过这个数,则失败
maxLatency 期望最大延时,如果实际最大延时超过这个,则失败
meanLatency 期望中位数延时

下面是使用了JUnitPerfTestRequirement的一个测试方法,需要和@JUnitPerfTest一起使用:

具体代码如下例:

@Test
@JUnitPerfTest(threads = 50,durationMs = 1200,warmUpMs = 100,maxExecutionsPerSecond = 110)
@JUnitPerfTestRequirement(percentiles = "90:7,95:7,98:7,99:8", executionsPerSec = 10_000, allowedErrorPercentage = 0.10f)
public void getServiceId() {

String result =demoPerfService.getServiceId("userid");
System.out.println(result);
Assert.assertNotNull(result);
}

运行之后,如果发现没有满足JUnitPerfTestRequirement定义,则报错:

java.lang.AssertionError: Test throughput threshold not achieved
Expected: is <true>
but: was <false>
Expected :is <true>

是不是很简单!

设置测试报告地址

JUnitPerf 有不同的测试报告,个人觉得HTML的测试报告比较实用,具体只需要:

@Rule
public JUnitPerfRule perfTestRule = new JUnitPerfRule(new HtmlReportGenerator("perf/report.html"));

完整的例子

public class DemoServiceTest {
@Rule
// public JUnitPerfRule perfTestRule = new JUnitPerfRule(new HtmlReportGenerator("perf/report.html"));
public JUnitPerfRule perfTestRule = new JUnitPerfRule();
DemoPerfService demoPerfService;
@Before
public void setupService(){
this.demoPerfService = new DemoPerfService();
}

@Test
@JUnitPerfTest(threads = 50,durationMs = 1200,warmUpMs = 100,maxExecutionsPerSecond = 110)
@JUnitPerfTestRequirement(percentiles = "90:7,95:7,98:7,99:8", executionsPerSec = 10_000, allowedErrorPercentage = 0.10f)
public void getServiceId() {

String result =demoPerfService.getServiceId("userid");
System.out.println(result);
Assert.assertNotNull(result);
}

@Test
@JUnitPerfTest(threads = 50,durationMs = 1200,warmUpMs = 100,maxExecutionsPerSecond = 110)
public void getServiceId_withoutTestRequirement() {

String result =demoPerfService.getServiceId("userid");
System.out.println(result);
Assert.assertNotNull(result);
}
}

最后可以再设定的目录中查看测试报告,测试报告和默认的HTML 测试报告是一致的.

一点问题

压力测试过程中,有时数据不能复用,举个例子来说,如果想测试完全没有访问redis缓存情况下,通过userid查询的user信息速度,那么压测的时候userid就不能复用,因为一旦访问了就会放入redis缓存而影响结果,这个可以通过使用其他的方法解决,比如曾今使用过BlockingQueue的方法进行过尝试,具体方法如下:

  1. 读取所有userid的文件
  2. 把userid放到一个BlockingQueue中
  3. 压测时获取userid通过BlockingQueue去获取

这样就解决了数据不能重复的方法,具体方法可以参考如下代码:

    static BlockingQueue<String> distinctIdQueue ;
@Rule
public JUnitPerfRule perfTestRule =
new JUnitPerfRule(new HtmlReportGenerator("data/report_test.html"));

@BeforeClass
public static void setupQueue() throws IOException {

distinctIdQueue = new LinkedBlockingQueue<>();
Files.readAllLines(
Paths.get("data/userid.txt")
).parallelStream().forEach(
item-> {
try {
distinctIdQueue.put(item);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
);

}

@Test
@JUnitPerfTest(threads = 50,durationMs = 1200,warmUpMs = 100,maxExecutionsPerSecond = 110)
@JUnitPerfTestRequirement(percentiles = "90:7,95:7,98:7,99:8", executionsPerSec = 10_000, allowedErrorPercentage = 0.10f)
public void getServiceId() {
String uesrId = distinctIdQueue.take();
String result =demoPerfService.getServiceId(userId);
System.out.println(result);
Assert.assertNotNull(result);
}


}
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 3 条回复 时间 点赞
seveniruby 将本帖设为了精华贴 07月28日 10:09

赞一个 基于junit的性能测试,不需要自己开线程,但是一般压测在linux下,还需要打包哟。

HeartBeat 回复

直接在本机运行的,没有打包。maven的项目的话,直接mvn test就可以了,或者在打包的时候不忽律test,就会在打包时运行.

对多线程有用处,用了java8的技术

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