手写java性能测试框架第二版

引言

依照领导要求区分了两种压测模式:固定次数压测和固定时间压测。此前一直沿用的都是固定次数,所以本次第二版剥离了固定次数的模式增加了固定时间的模式。

这是第一版:性能测试框架

第二版的threadbase代码如下

package com.fun.base.constaint;
import com.fun.frame.SourceCode;
import java.util.concurrent.CountDownLatch;
/**
 * 多线程任务基类,可单独使用
 */
public abstract class ThreadBase extends SourceCode implements Runnable {
    /**
     * 计数锁
     * 

* 会在concurrent类里面根据线程数自动设定 *

*/ 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;
/**
 * 请求时间限制的多线程类,限制每个线程执行的次数
 *
 * 

* 通常在测试某项用例固定时间的场景下使用,可以提前终止测试用例 *

* * @param 闭包参数传递使用,Groovy脚本会有一些兼容问题,部分对象需要tostring获取参数值 */ public abstract class ThreadLimitTimes 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 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;
/**
 * 请求时间限制的多线程类,限制每个线程执行的时间
 * 

* 通常在测试某项用例固定时间的场景下使用,可以提前终止测试用例 *

* * @param 闭包参数传递使用,Groovy脚本会有一些兼容问题,部分对象需要tostring获取参数值 */ public abstract class ThreadLimitTime 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 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
     * 

此方法只适应与单个请求的重复请求,对于有业务联系的请求暂时不能适配

* * @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
     * 

此方法只适应与单个请求的重复请求,对于有业务联系的请求暂时不能适配

* * @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 threadLimitTime = new ThreadLimitTime(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性能测试框架第二版)