使用Jmeter聚合報告生成對比圖表


背景

最近在幫別的項目組執行性能測試,使用的工具是Jmeter。接口錄制和參數化前一個人已經做好了,我主要的工作就是執行腳本,撰寫測試報告。事情並不復雜,可做起來卻極為耗時。

首先,由於有6組賬號,分別對應6個不同的BU,而每個BU又需要執行1、10、20、30四種壓力模式。如果使用GUI模式跑,就需要執行24次,還需要每次自己改參數,實在是費心費力。

其次,使用Jmeter插件生成聚合結果后,要根據結果出一份報告,。在我之前做的同事,由於是第一輪測試,也就無從比較,只是從接口、頁面、錯誤率三個維度寫了一份報告。而我則需要根據本次和上次的結果,生成圖表,以便直觀地展示結果。剛開始做這件事時,我是根據需求,找到對應的接口和頁面,分別挪到Excel里,利用Excel生成圖表。可是既容易錯,還容易瞎,實在是折磨人。

解決方案

1

為了解決第一個問題,我的思路是找到Jmeter測試腳本的配置文件,復制多份,批量改成不同的配置,再利用bat腳本每次執行多個。

先將原來的測試腳本Jmx文件復制多份,按環境分成不同的文件夾,再按線程數整理進去,如下圖:

 

 

 

 

因為Jmx文件其實都是xml格式,里面存儲了腳本的配置,於是就使用VS Code打開文件夾,進行批量替換,這樣很快就能完成配置工作。

 

 

 

之后再寫bat腳本,以命令行模式執行jmx腳本,並生成測試報告。

注意在批處理文件中執行多條命令時,如果期望上一條執行完畢再繼續執行下一條(也就是順序調用),需要使用call方法。大致如下:

 

 

call %userprofile%\Desktop\apache-jmeter-3.3\bin\jmeter.bat -n -t 'CP BU.jmx' -l test_report.csv -e -o cp_test_report
call %userprofile%\Desktop\apache-jmeter-3.3\bin\jmeter.bat -n -t 'FA BU.jmx' -l test_report.csv -e -o fa_test_report

%userprofile%是系統變量,代表用戶目錄,形如C:\Users\xxx。這樣調用可以提高復用性,之后用到的電腦只需要將jmeter放在桌面,即可運行。

-n non-gui 以非GUI模式運行

-t test-file 要執行的腳本文件

-l logfile 記錄結果的文件,之后可以用來生成聚合報告

-o output html報告保存的路徑

 

 這樣每次執行執行每種線程數的批處理文件,就可以自動執行並生成報表了。

其實還可以對生成報告的路徑,再做參數化配置,按照一定規則整合在一起。而且還可以將多線程的bat文件,再一起執行,這樣就更省事。這些都是可優化的地方

2

對比報告這部分就要麻煩些了。初步的思路是從新舊報告宏讀取數據,再使用生成圖表的庫生成對比圖。有了對比圖,要說的話就會少很多了,畢竟一圖勝千言嘛。

之前同事其實是直接從Jmeter中粘貼出來的報告,與腳本生成的html報告還有不一樣的地方。況且,html文件不好讀取數據,很難與excel中的數據對比。

最省腦子的方法自然是我按照原來的方式重新跑一遍,一一把數據粘貼出來,這樣結果的格式就一樣了,可是復用性太差,就不考慮了。之后想用笨方法,利用插件從打開的html報告中讀出表格。試了一圈,Chrome的插件要么只能用於http開頭的網頁,要么就是不起作用。又試了下UI Path(RPA工具,最近跟過一些教程),提取是成功了,可是好像和頁面上的行數不一致,大概是某些元素的沒有被識別為表格元素。無奈之下,只能想想能不能利用現有的報告生成類似之前版本的報告。有查到用jemter命令將jtl(jmeter的測試結果)轉換為聚合報告,可是腳本無法執行,說是缺插件,奈何jmeter上裝插件總是失敗,也沒辦法。只得自己在jemter界面上試試,在聚合報告插件中導入之前生成的csv文件。這下成功了,也稍微理解了這些報告的作用。這些插件其實就是將日志文件重新計算整理,展示出最關注的幾點。

 

這樣就保證數據格式一致了。接下來就是考慮讀取數據了。我最先想到的是用pandas中的Dataframe格式存儲數據。

寫個讀取的方法:

def read_reports_csv(folder):
    cp_df = pd.read_csv(os.path.join(folder, 'cp.csv'))
    mc_df = pd.read_csv(os.path.join(folder, 'mc.csv'))
    mcp113_df = pd.read_csv(os.path.join(folder, 'mcp113.csv'))
    mcproject_df = pd.read_csv(os.path.join(folder, 'mcproject.csv'))
    pa_df = pd.read_csv(os.path.join(folder, 'pa.csv'))
    fa_df = pd.read_csv(os.path.join(folder, 'fa.csv'))
    return cp_df, mc_df, mcp113_df, mcproject_df, pa_df, fa_df

至於生成圖表,我想到的是pyecharts。

繪制圖表的示例如下:

from pyecharts.charts import Bar
from pyecharts import options as opts


bar = (
Bar({"width": "800px", "height": "750px", }) # 初始化圖表寬和高
.add_xaxis(list(last_label)) # x軸的數
.add_yaxis('Response Time Average This Time',list(this_average)) # 增加y軸,本次結果
.add_yaxis('Response Time Average Last TIme',list(last_average)) # 增加y軸,上次結果
.set_global_opts( # 設置全局設置
    title_opts=opts.TitleOpts(title='接口平均相應時間對比圖'), # 設置標題
    xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=15)), # 設置x周,這里是將文字傾斜,便於顯示較長的文字
    legend_opts=opts.LegendOpts(is_show=True, pos_right=10) # 設置圖例
)
)

生成圖表這塊,在網上查了很久,主要是參數配置不太理解。最后都是在官方文檔中找到了最后答案。不得不說,還是官方文檔靠譜,百度里搜索出來的結果有時能解燃眉之急,有時卻是東拼西湊,質量不高。還是多用Google吧。不過pyechart本身是源自百度的庫,估計國外用的人不多,資料大概也不多。

接下來是就往圖表里塞數據了,這里也是問題最多的地方,主要有以下幾點:

1.前后執行的接口並不是完全一致,沒辦法直接通過Label標簽排序,將要比較的數據對齊。

2.有些接口請求的參數是動態變化的,沒辦法將接口名寫死。

可見,數據清理將是重頭,會決定之后生成的圖表是否正確。我的解決思路是,將要比較的接口和頁面分別參數化,再拿着要比較的數據,取其Label字段,分別在新舊數據中搜索,生成新舊待比較的數據集,再將數據排列對齊,保證順序一致。Dataframe支持的操作其實已經很多了,就我目前了解的,沒有找到現成方案,就自己寫了些小方法,實現這些目標。具體代碼如下:

def df_contains(df, partial_labels):
    '''
    這一步是為了找出要對比的數據
    遍歷列表,在Dataframe中匹配,凡是包含當前字符串的,都拿出來
    '''
    result_df = None
    for label in partial_labels:
        x = df[df['Label'].str.contains(label)]
        if result_df is None:
            result_df = x
        else:
            if not x.empty:
                result_df = result_df.append(x, ignore_index=True)
    return result_df.drop_duplicates(subset=['Label', 'Average','Median'], keep='first')
def replace_digits_in_df(df, label):
    '''
    這一步是為了取出label中的數字
    Jmeter錄制的腳本中,每次請求前面都會加上序號,影響排序,需要統一去掉
    當然也許Jmeter中本身就可以設置,只是我不知道
    '''
    for row in df.iterrows():
        _ = row[1].Label
        df.loc[row[0], label] = re.sub('\d+', '', _)
    return df
def draw_api(last_df, this_df, column):
    '''
    last_df: 上一次結果,pd.Dataframe
    this_df: 本次結果,pd.Dataframe
    return: 柱狀對比圖,可在notebook中繪制,也可直接導出html
    '''
    last_temp = replace_digits_in_df(last_df,'Label')
    last = df_contains(last_temp, api_labels).sort_values(by=['Label'])
    
    this_temp = replace_digits_in_df(this_df,'Label')
    this = df_contains(this_df,api_labels).sort_values(by=['Label'])
   
    print(this.Label)
    print('--------')
    print(last.Label)

    # 下面都是為了取出新舊待比較數據集中的交集,避免數據錯位
    this_del_index = this.append(last, sort=False).drop_duplicates(subset=['Label'], keep=False).index
    this = this.drop(this_del_index)
    
    last_del_index = last.append(this, sort=False).drop_duplicates(subset=['Label'], keep=False).index
    last = last.drop(last_del_index)
    

    
    this_average = this[column]
    this_label = this.Label
    last_average = last[column]
    last_label = last.Label
    

    bar = (
    Bar({"width": "800px", "height": "750px", })
    .add_xaxis(list(last_label))
    .add_yaxis('Response Time Average This Time',list(this_average))
    .add_yaxis('Response Time Average Last TIme',list(last_average))
    .set_global_opts(
        title_opts=opts.TitleOpts(title='接口平均相應時間對比圖'),
        xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=15)),
        legend_opts=opts.LegendOpts(is_show=True, pos_right=10)
    )
    )
    return bar

當然,這些方法也是前前后后嘗試了很多次,慢慢寫出來的規則。經過對比,執行的兩輪中,沒有數據錯位的情況。其實這部分也是最費時間的。

另外,在jupyter notebook中可以實時查看生成的圖表,很是方便,推薦使用。只需要對最后生成的圖表對象,調用render_notebook()方法即可。最后生成的對比圖如下:

 

 

 

代碼地址:

https://github.com/MRFF/Learning-Python/blob/master/compare_reports.py

參考鏈接:

https://pandas.pydata.org/pandas-docs/stable/

https://pyecharts.org/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM