软件编程
位置:首页>> 软件编程>> java编程>> 手写java性能测试框架第二版

手写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

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com