在進行性能測試的過程中,通常可能會遇到長時間測試的情況,但是在這過程中很難控制壓測進度(偷偷告訴你終止性能測試並輸出報告可以實現)。
爲了解決無法實時掌控測試進度的問題,我寫了一個多線程類,主要的功能就是異步完成對性能測試進度的收集和輸出。
思路如下:性能測試模型分兩類(固定線程和固定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 * 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()
方法。
/**
* 執行多線程任務
* 默認取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,非著名測試開發,文章記錄學習和感悟,歡迎關注,交流成長。
-
2020年FunTester自我總結 -
固定QPS壓測初試 -
如何測試概率型業務接口 -
測試模型中理解壓力測試和負載測試 -
基於代碼的自動化和無代碼自動化 -
物聯網測試 -
功能測試知多少 -
敏捷測試二三事 -
自動化測試生命週期 -
moco固定QPS接口升級補償機制 -
性能測試如何減少本機誤差
本文分享自微信公衆號 - FunTester(NuclearTester)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。