性能测试中异步展示测试进度

2021-02-24 10:07:35 浏览数 (1)

在进行性能测试的过程中,通常可能会遇到长时间测试的情况,但是在这过程中很难控制压测进度(偷偷告诉你终止性能测试并输出报告可以实现)。

为了解决无法实时掌控测试进度的问题,我写了一个多线程类,主要的功能就是异步完成对性能测试进度的收集和输出。

思路如下:性能测试模型分两类(固定线程固定QPS),测试的模式两种(定时定量),为了兼容这两种模型和两种模式,我用了一个类,使用不同的标记属性来区分。然后根据具体的限制类型(时间或者次数)来获取不同的进度值,通过简单的运算得到结果,利用之前性能测试中图形化输出测试数据文章中用到的符合来输出结果。

多线程类

代码语言:javascript复制
package com.fun.frame.execute;

import com.fun.base.constaint.FixedQpsThread;
import com.fun.base.constaint.ThreadBase;
import com.fun.base.constaint.ThreadLimitTimeCount;
import com.fun.base.constaint.ThreadLimitTimesCount;
import com.fun.base.exception.ParamException;
import com.fun.config.HttpClientConstant;
import com.fun.frame.SourceCode;
import com.fun.utils.Time;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 用于异步展示性能测试进度的多线程类
 */
public class Progress extends SourceCode implements Runnable {

    private static Logger logger = LoggerFactory.getLogger(Progress.class);

    /**
     * 总开关,是否运行,默认true
     */
    private boolean st = true;

    /**
     * 是否次数模型
     */
    public boolean isTimesMode;

    /**
     * 多线程任务基类对象,本类中不处理,只用来获取值,若使用的话请调用clone()方法
     */
    private ThreadBase base;

    /**
     * 限制条件
     */
    private int limit;

    /**
     * 非精确时间,误差可以忽略
     */
    private long startTime = Time.getTimeStamp();

    /**
     * 描述
     */
    private String taskDesc;

    public Progress(ThreadBase base, String desc) {
        this(base);
        this.base = base;
        this.taskDesc = desc;
    }

    private Progress(ThreadBase base) {
        if (base instanceof ThreadLimitTimeCount) {
            this.isTimesMode = false;
            this.limit = ((ThreadLimitTimeCount) base).time;
        } else if (base instanceof ThreadLimitTimesCount) {
            this.isTimesMode = true;
            this.limit = ((ThreadLimitTimesCount) base).times;
        } else if (base instanceof FixedQpsThread) {
            FixedQpsThread fix = (FixedQpsThread) base;
            this.isTimesMode = fix.isTimesMode;
            this.limit = fix.limit;
        } else {
            ParamException.fail("创建进度条对象失败!");
        }
    }

    @Override
    public void run() {
        int pro = 0;
        while (st) {
            sleep(HttpClientConstant.LOOP_INTERVAL);
            if (isTimesMode) {
                pro = (int) (base.executeNum * 1.0 / limit * BUCKET_SIZE * 2);
            } else {
                pro = (int) ((Time.getTimeStamp() - startTime) * 1.0 / limit * BUCKET_SIZE * 2);
            }
            if (pro >= BUCKET_SIZE * 2) break;
            logger.info("{}测试进度:{}  {}", taskDesc, getManyString(getPercent(8), pro), getPercent(getPercent(BUCKET_SIZE * 2, pro)));
        }
    }

    /**
     * 关闭线程,防止死循环
     */
    public void stop() {
        st = false;
        logger.info("{}测试进度:{}  {}", taskDesc, getManyString(getPercent(8), BUCKET_SIZE * 2), "100%");
    }


}

使用Demo

两种测试模型执行类的代码都差不多,这里在start()方法中添加一个线程即可,在结束的时候执行一下stop()方法。

代码语言:javascript复制

  /**
     * 执行多线程任务
     * 默认取list中thread对象,丢入线程池,完成多线程执行,如果没有threadname,name默认采用desc 线程数作为threadname,去除末尾的日期
     */
    public PerformanceResultBean start() {
        Progress progress = new Progress(threads.get(0), desc.replaceAll("\d{14}$", EMPTY));
        new Thread(progress).start();
        startTime = Time.getTimeStamp();
        for (int i = 0; i < threadNum; i  ) {
            ThreadBase thread = threads.get(i);
            if (StringUtils.isBlank(thread.threadName)) thread.threadName = desc.replaceAll("\d{14}$", EMPTY)   i;
            thread.setCountDownLatch(countDownLatch);
            executorService.execute(thread);
        }
        shutdownService(executorService, countDownLatch);
        endTime = Time.getTimeStamp();
        progress.stop();
        threads.forEach(x -> {
            if (x.status()) failTotal  ;
            errorTotal  = x.errorNum;
            executeTotal  = x.executeNum;
        });
        logger.info("总计{}个线程,共用时:{} s,执行总数:{},错误数:{},失败数:{}", threadNum, Time.getTimeDiffer(startTime, endTime), executeTotal, errorTotal, failTotal);
        return over();
    }

另外一个固定QPS压测模式探索中的使用我就不写了。

实际效果

这里输出的都是字符串,这里复制一批展示效果。

代码语言:javascript复制
16:42:33 INFO - 教学活动列表测试进度:  0%
16:42:38 INFO - 教学活动列表测试进度:██  4.34%
16:42:48 INFO - 教学活动列表测试进度:████  8.69%
16:42:53 INFO - 教学活动列表测试进度:█████  10.86%
16:42:58 INFO - 教学活动列表测试进度:██████  13.04%
16:43:03 INFO - 教学活动列表测试进度:███████  15.21%
16:43:08 INFO - 教学活动列表测试进度:████████  17.39%
16:43:13 INFO - 教学活动列表测试进度:█████████  19.56%
16:43:18 INFO - 教学活动列表测试进度:██████████  21.73%
16:43:28 INFO - 教学活动列表测试进度:███████████  23.91%
16:43:33 INFO - 教学活动列表测试进度:████████████  26.08%
16:43:43 INFO - 教学活动列表测试进度:██████████████  30.43%
16:43:48 INFO - 教学活动列表测试进度:████████████████  34.78%
16:43:53 INFO - 教学活动列表测试进度:█████████████████  36.95%

  • Gitee地址https://gitee.com/fanapi/tester
  • GitHub地址https://github.com/JunManYuanLong/FunTester

0 人点赞