手写java性能测试框架第二版
作者:FunTester 发布时间:2023-03-15 14:07:31
标签: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性能测试框架的资料请关注脚本之家其它相关文章!
来源:http://169p.cn/86tb


猜你喜欢
- 本文实例讲述了Android编程实现canvas绘制饼状统计图功能。分享给大家供大家参考,具体如下:本例的目的是实现一个简单的饼状统计图,效
- 本文主要给大家介绍java的InputStream 流的使用。(1)FileInputstream: 子类,读取数据的通道使用步骤:1.获取
- 中断线程线程的thread.interrupt()方法是中断线程,将会设置该线程的中断状态位,即设置为true,中断的结果线程是死亡、还是等
- 一、 DataTable转换到List<T>/// <summary> /// TableT
- 很多时候需要先判断当前用户的网络,才会继续之后的一些处理逻辑。但网络类型获取这一块,我用我自己的的手机调试时遇到一些问题,这里记录一下。一加
- git忽略的原理:git设置本地忽略必须保证git的远程仓库分支上没有这个要忽略的文件,如果远程分支上存在这个文件,本地在设置ignore
- public class FileAccess{//储存所有文件夹名private ArrayList dirs;public FileAc
- 本文实例讲述了ActiveMQ在C#中的应用。分享给大家供大家参考,具体如下:ActiveMQ是个好东东,不必多说。ActiveMQ提供多种
- 最近在研究springboot实现FastJson解析json数据的方法,那么今天也算个学习笔记吧!添加jar包:<dependenc
- 1. mapper.xml设置resultTyperesultType="com.alibaba.fastjson.JSONObj
- this总要有个事物来代表类的当前对象,就像C++中的this指针一样,Java中的this关键字就是代表当前对象的引用。它有三个主要的作用
- 自己写的一个日历记事本效果图 具体步骤:1.添加控件SkinEngine。 1.右键“工具箱”。“添加选项卡”,取名“皮肤”。
- 引言在开发中有时候经常需要一些Http请求,请求数据,下载内容,也有一些简单的分布式应用直接使用Http请求作为跨应用的交互协议。在Java
- 代理对象的生成方法是:Proxy.newProxyInstance(...) ,进入这个方法内部,一步一步往下走会发现会调用ProxyGen
- 题目描述:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将
- 目录前言实践部分测试部分总结前言今天跟小伙伴们分享一个实战内容,使用Spring Boot+Shiro实现一个简单的Http认证。场景是这样
- 目录事件最基本的用法理解路由事件WPF中使用路由事件升级了传统应用开发中的事件,在WPF中使用路由事件能更好的处理事件相关的逻辑,我们从这篇
- 以前在别的地方见过一个通过调用系统API实现屏幕截图的例子,从内心来说我不太喜欢在C#代码中出现这种情况,现在什么都讲“和谐”,我觉得这种做
- 手写一个通用加载中、显示数据、加载失败、空数据的LoadingView框架。定义3个布局:加载中,加载失败,空数据加载中:<?xml
- 内存映射文件是利用虚拟内存把文件映射到进程的地址空间中去,在此之后进程操作文件,就像操作进程空间里的地址一样了,比如使用c语言的 memcp