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

Posted FunTester

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了性能测试中异步展示测试进度相关的知识,希望对你有一定的参考价值。

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

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

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

多线程类

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 * 2break;
            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()方法。


  /**
     * 执行多线程任务
     * 默认取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();
    }

另外一个中的使用我就不写了。

实际效果

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

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
FunTester,非著名测试开发,文章记录学习和感悟,欢迎关注,交流成长。

点击阅读原文,查看公众号历史文章
- END -


以上是关于性能测试中异步展示测试进度的主要内容,如果未能解决你的问题,请参考以下文章

单元测试不了解 XCTest 期望的异步 UI 代码?

JMeter Web性能测试增强版系列1

四则运算单元测试

增加任务中心,优化性能测试指标展示方式,MeterSphere开源持续测试平台v1.11.0发布

异步Mongo驱动的性能测试——响应式Spring的道法术器

JMeter + Grafana + influxdb 性能监控平台搭建