这篇文章主要为大家介绍了手写java性能测试框架第二版实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
引言
依照领导要求区分了两种压测模式:固定次数压测和固定时间压测。此前一直沿用的都是固定次数,所以本次第二版剥离了固定次数的模式增加了固定时间的模式。
这是第一版:性能测试框架
第二版的threadbase代码如下
package com.fun.base.constaint;
import com.fun.frame.SourceCode;
import java.util.concurrent.CountDownLatch;
/**
* 多线程任务基类,可单独使用
*/
public abstract class ThreadBase<T> extends SourceCode implements Runnable {
/**
* 计数锁
* <p>
* 会在concurrent类里面根据线程数自动设定
* </p>
*/
CountDownLatch countDownLatch;
/**
* 用于设置访问资源
*/
public T t;
protected ThreadBase() {
super();
}
/**
* groovy无法直接访问t,所以写了这个方法
*
* @return
*/
public String getT() {
return t.toString();
}
/**
* 运行待测方法的之前的准备
*/
protected abstract void before();
/**
* 待测方法
*
* @throws Exception
*/
protected abstract void doing() throws Exception;
/**
* 运行待测方法后的处理
*/
protected abstract void after();
public void setCountDownLatch(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
}
固定次数模式的压测虚拟类
package com.fun.base.constaint;
import com.fun.frame.excute.Concurrent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import static com.fun.utils.Time.getTimeStamp;
/**
* 请求时间限制的多线程类,限制每个线程执行的次数
*
* <p>
* 通常在测试某项用例固定时间的场景下使用,可以提前终止测试用例
* </p>
*
* @param <T> 闭包参数传递使用,Groovy脚本会有一些兼容问题,部分对象需要tostring获取参数值
*/
public abstract class ThreadLimitTimes<T> extends ThreadBase {
private static final Logger logger = LoggerFactory.getLogger(ThreadLimitTimes.class);
/**
* 任务请求执行次数
*/
public int times;
/**
* 用于设置访问资源
*/
public T t;
public ThreadLimitTimes(T t, int times) {
this(times);
this.t = t;
}
public ThreadLimitTimes(int times) {
this();
this.times = times;
}
protected ThreadLimitTimes() {
super();
}
/**
* groovy无法直接访问t,所以写了这个方法
*
* @return
*/
public String getT() {
return t.toString();
}
@Override
public void run() {
try {
before();
List<Long> t = new ArrayList<>();
long ss = getTimeStamp();
for (int i = 0; i < times; i++) {
long s = getTimeStamp();
doing();
long e = getTimeStamp();
t.add(e - s);
}
long ee = getTimeStamp();
logger.info("执行次数:{},总耗时:{}", times, ee - ss);
Concurrent.allTimes.addAll(t);
} catch (Exception e) {
logger.warn("执行任务失败!", e);
} finally {
if (countDownLatch != null)
countDownLatch.countDown();
after();
}
}
/**
* 运行待测方法的之前的准备
*/
protected abstract void before();
/**
* 待测方法
*
* @throws Exception
*/
protected abstract void doing() throws Exception;
/**
* 运行待测方法后的处理
*/
protected abstract void after();
}
固定时间模式虚拟类
package com.fun.base.constaint;
import com.fun.frame.excute.Concurrent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import static com.fun.utils.Time.getTimeStamp;
/**
* 请求时间限制的多线程类,限制每个线程执行的时间
* <p>
* 通常在测试某项用例固定时间的场景下使用,可以提前终止测试用例
* </p>
*
* @param <T> 闭包参数传递使用,Groovy脚本会有一些兼容问题,部分对象需要tostring获取参数值
*/
public abstract class ThreadLimitTime<T> extends ThreadBase {
/**
* 全局的时间终止开关
*/
private static boolean key = false;
private static final Logger logger = LoggerFactory.getLogger(ThreadLimitTime.class);
/**
* 任务请求执行时间,单位是秒
*/
public int time;
/**
* 用于设置访问资源
*/
public T t;
public ThreadLimitTime(T t, int time) {
this(time);
this.t = t;
}
public ThreadLimitTime(int time) {
this();
this.time = time * 1000;
}
protected ThreadLimitTime() {
super();
}
@Override
public void run() {
try {
before();
List<Long> t = new ArrayList<>();
long ss = getTimeStamp();
while (true) {
long s = getTimeStamp();
doing();
long e = getTimeStamp();
t.add(e - s);
if ((e - ss) > time || key) break;
}
long ee = getTimeStamp();
logger.info("执行时间:{} s,总耗时:{}", time / 1000, ee - ss);
Concurrent.allTimes.addAll(t);
} catch (Exception e) {
logger.warn("执行任务失败!", e);
} finally {
if (countDownLatch != null)
countDownLatch.countDown();
after();
}
}
/**
* 用于在某些情况下提前终止测试
*/
public static void stopAllThread() {
key = true;
}
}
这里我多加了一个终止测试的key,暂时没有用,以防万一。之所以没有采用另起线程去计时原因有二:进行测试过程中无论如何都会记录时间戳,多余的计算比较时间戳大小消耗性能很低,可以忽略;另起线程设计麻烦,在发生意外情况时缺少第二种保险措施。
HTTPrequestbase为基础的多线程类
下面是两种实现类的Demo,以HTTPrequestbase作为基础的多线程类。
固定次数模式的多线程类
/**
* http请求多线程类
*/
public class RequestThreadTimes extends ThreadLimitTimes {
static Logger logger = LoggerFactory.getLogger(RequestThreadTimes.class);
/**
* 请求
*/
public HttpRequestBase request;
/**
* 单请求多线程多次任务构造方法
*
* @param request 被执行的请求
* @param times 每个线程运行的次数
*/
public RequestThreadTimes(HttpRequestBase request, int times) {
this.request = request;
this.times = times;
}
@Override
public void before() {
GCThread.starts();
}
@Override
protected void doing() throws Exception {
getResponse(request);
}
@Override
protected void after() {
GCThread.stop();
}
/**
* 多次执行某个请求,但是不记录日志,记录方法用 loglong
* <p>此方法只适应与单个请求的重复请求,对于有业务联系的请求暂时不能适配</p>
*
* @param request 请求
* @throws IOException
*/
void getResponse(HttpRequestBase request) throws IOException {
CloseableHttpResponse response = ClientManage.httpsClient.execute(request);
String content = FanLibrary.getContent(response);
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK)
logger.warn("响应状态码:{},响应内容:{}", content, response.getStatusLine());
response.close();
}
}
固定时间模式的多线程类
package com.fun.frame.thead;
import com.fun.base.constaint.ThreadLimitTime;
import com.fun.frame.httpclient.ClientManage;
import com.fun.frame.httpclient.FanLibrary;
import com.fun.frame.httpclient.GCThread;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
/**
* http请求多线程类
*/
public class RequestThreadTime extends ThreadLimitTime {
static Logger logger = LoggerFactory.getLogger(RequestThreadTime.class);
/**
* 请求
*/
public HttpRequestBase request;
/**
* 单请求多线程多次任务构造方法
*
* @param request 被执行的请求
* @param times 每个线程运行的次数
*/
public RequestThreadTime(HttpRequestBase request, int time) {
this.request = request;
this.time = time;
}
@Override
public void before() {
GCThread.starts();
}
@Override
protected void doing() throws Exception {
getResponse(request);
}
@Override
protected void after() {
GCThread.stop();
}
/**
* 多次执行某个请求,但是不记录日志,记录方法用 loglong
* <p>此方法只适应与单个请求的重复请求,对于有业务联系的请求暂时不能适配</p>
*
* @param request 请求
* @throws IOException
*/
void getResponse(HttpRequestBase request) throws IOException {
CloseableHttpResponse response = ClientManage.httpsClient.execute(request);
String content = FanLibrary.getContent(response);
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK)
logger.warn("响应状态码:{},响应内容:{}", content, response.getStatusLine());
response.close();
}
}
其中可以发现,差别就在于属性time还是times的设定。
使用Demo:
package com.fun;
import com.fun.base.constaint.ThreadLimitTime;
import com.fun.frame.SourceCode;
import com.fun.frame.excute.Concurrent;
import java.util.ArrayList;
import java.util.List;
public class AR extends SourceCode {
public static void main(String[] args) {
ThreadLimitTime<Object> threadLimitTime = new ThreadLimitTime<Object>(10) {
/**
* 运行待测方法的之前的准备
*/
@Override
protected void before() {
}
/**
* 待测方法
*
* @throws Exception
*/
@Override
protected void doing() throws Exception {
AR.test();
}
/**
* 运行待测方法后的处理
*/
@Override
protected void after() {
}
};
new Concurrent(threadLimitTime,5).start();
FanLibrary.testOver();
}
public static void test() {
synchronized (AR.class) {
sleep(100);
output("fun");
}
}
}
剩下的mysql和redis以及dubbo的Demo就不写了,各位看官看着发挥即可,更多关于java性能测试框架的资料请关注编程学习网其它相关文章!
沃梦达教程
本文标题为:手写java性能测试框架第二版
基础教程推荐
猜你喜欢
- Java数据结构之对象比较详解 2023-03-07
- Java并发编程进阶之线程控制篇 2023-03-07
- Java实现查找文件和替换文件内容 2023-04-06
- springboot自定义starter方法及注解实例 2023-03-31
- JDK数组阻塞队列源码深入分析总结 2023-04-18
- Java文件管理操作的知识点整理 2023-05-19
- java实现多人聊天系统 2023-05-19
- Java实现线程插队的示例代码 2022-09-03
- ConditionalOnProperty配置swagger不生效问题及解决 2023-01-02
- java基础知识之FileInputStream流的使用 2023-08-11