前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >性能测试框架第二版

性能测试框架第二版

作者头像
FunTester
发布2019-12-05 17:42:16
3810
发布2019-12-05 17:42:16
举报
文章被收录于专栏:FunTesterFunTester

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

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

第二版的threadbase代码如下:

代码语言:javascript
复制
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;
    }


}

余下是固定次数模式的压测虚拟类:

代码语言:javascript
复制
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();


}

余下是固定时间模式虚拟类:

代码语言:javascript
复制
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,暂时没有用,以防万一。之所以没有采用另起线程去计时原因有二:进行测试过程中无论如何都会记录时间戳,多余的计算比较时间戳大小消耗性能很低,可以忽略;另起线程设计麻烦,在发生意外情况时缺少第二种保险措施。

下面是两种实现类的Demo,以HTTPrequestbase作为基础的多线程类。下面是固定次数模式的多线程类:

代码语言:javascript
复制
/**
 * 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();
    }
}

下面是固定时间模式的多线程类:

代码语言:javascript
复制
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:

代码语言:javascript
复制
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就不写了,各位看官看着发挥即可。


本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-12-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 FunTester 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档