性能測試中異步展示測試進度

在進行性能測試的過程中,通常可能會遇到長時間測試的情況,但是在這過程中很難控制壓測進度(偷偷告訴你終止性能測試並輸出報告可以實現)。

爲了解決無法實時掌控測試進度的問題,我寫了一個多線程類,主要的功能就是異步完成對性能測試進度的收集和輸出。

思路如下:性能測試模型分兩類(固定線程固定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();
    }

另外一個固定QPS壓測模式探索中的使用我就不寫了。

實際效果

這裏輸出的都是字符串,這裏複製一批展示效果。

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 -


本文分享自微信公衆號 - FunTester(NuclearTester)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章