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

    下面是两种实现类的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就不写了,各位看官看着发挥即可。


    技术类文章精选

    非技术文章精选

  • 相关阅读:
    SQLite无法使用drop column删除表字段解决办法
    Selenium之自动发送163邮件(转自https://www.cnblogs.com/zhang-da/p/12230415.html)
    frp 内网穿透
    smart.supor.com
    python colorama模块
    nohup和&后台运行,进程查看及终止
    Beef搭建并通过Nginx绑定域名
    How to Install Ruby on CentOS/RHEL 7/6
    Linux环境下安装python3
    启用IIS Express SSL(Https)的注意事项
  • 原文地址:https://www.cnblogs.com/FunTester/p/11982709.html
Copyright © 2011-2022 走看看