手写java性能测试框架第二版
作者:FunTester
这篇文章主要为大家介绍了手写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性能测试框架的资料请关注脚本之家其它相关文章!