jinja2快速實現自定義的robotframework的測試報告


一、背景

RF的結果報告可以方便我們查看每一條用例集、用例的執行結果統計,但是有的項目涉及到一些數據的比對,希望能夠直觀到看到數據,原生的測試報告就無法滿足這個需求了。

  • 原生的報告
    20200904144123
  • 項目需求報告格式
    20200904144658

二、解決方案

2.1 流程圖

20200904150324

  • 解析output.xml,將用例的相關信息和執行結果獲取
  • 通過API和數據庫獲取需要展示的數據
  • 將上述兩步的數據封裝到一個數據列表中,方便后面進行模板渲染
  • 根據需求畫HTML的報告模板
  • 對模板進行數據填充渲染,生成報告文件
  • 郵件發送報告
2.2 output.xml解析

測試用例相關的信息和運行結果,我們可以通過解析RF的output.xml文件來進行獲取

2.2.1獲取用例運行情況的統計

20200904151717

import xml.dom.minidom
import xml.etree.ElementTree

# 打開xml文檔
dom = xml.dom.minidom.parse('E:\\robot\\fightdata_yuce\\results\\output.xml')
root2 = xml.etree.ElementTree.parse('E:\\robot\\fightdata_yuce\\results\\output.xml')

# 得到文檔元素對象
root = dom.documentElement
total = root.getElementsByTagName('total');
total_len = len(total)
# total的stat節點個數
total2 = root2.getiterator("total")
total_stat_num = len(total2[total_len-1].getchildren())
statlist = root.getElementsByTagName('stat');

def get_total_statistics():
    list = []
    for i in range(0,total_stat_num):
        d = dict()
        d['fail'] = int(statlist[i].getAttribute("fail"))#失敗用例數
        d['pass'] = int(statlist[i].getAttribute("pass"))#成功用例數
        d['total'] = d['fail']+d['pass']#用例總數
        d['percent'] = ('{:.2%}'.format(d['pass'] / d['total']))#用例百分比
        list.append(d)
    return list
2.2.2 獲取用例信息
  • 用例的組織結構
    20200904155335
  • 獲取用例信息和執行結果
    用例結構是多個suite,每個suite下有4條case
    20200904155707
import xml.dom.minidom
import xml.etree.ElementTree

# 打開xml文檔
dom = xml.dom.minidom.parse('E:\\robot\\xxx\\results\\output.xml')
root2 = xml.etree.ElementTree.parse('E:\\robot\\xxx\\results\\output.xml')
tree3=root2.getroot()
# 獲取suite下的子節點
def getcase():
    casedict = {}
    testlist2 = []
    for elem in tree3.iterfind('suite/suite'):
        a = elem.attrib
        suitedict = {}
        testlist2.append(suitedict) #每一個用例集合存入列表
        testlist = []
        suitename = a['name']#獲取用例結合的名字
        for test in elem.iter(tag='test'):
            b=test.attrib
            for data in test.iterfind('status'):
                 casename = b['name'] #獲取用例的名字
                 c=data.attrib
                 status=c['status'] #獲取每條用例的執行結果
                 casedict['casename'] = casename #用例名字存入字典
                 casedict['status'] = status #用例執行結果存入字典
            testlist.append(casedict) #每一條用例的名字和執行結果作為字典存入列表
            casedict = {}
            suitedict['suitename']=suitename
            suitedict['test']=testlist
    return testlist2   #最終返回的就是[{'suitename': 'xxx', 'test': [{'casename': '01 xxx', 'status': 'PASS'},
                                      #{'casename': '02 xxx', 'status': 'PASS'}
2.3 數據填充

通過前面獲取的獲取,填充到jinja2的模板中,會生成另外一個有數據的html文件

from jinja2 import Environment, FileSystemLoader
import parsexml


def generate_html(data):
    env = Environment(loader=FileSystemLoader('./'))   # 加載模板
    template = env.get_template('report.html')
    # template.stream(body).dump('result.html', 'utf-8')
    data=parsexml.get_total_statistics()#獲取解析的xml的用例統計數據
    data2=parsexml.getcase()#獲取測試用例信息和執行結果
    with open("result.html", 'w',encoding='utf-8') as fout:
        html_content = template.render(data=data,data2=data2)
        fout.write(html_content)    #  寫入模板 生成html
2.4 jinja2模板介紹

jinja2模板的原理就是,通過先創建一個html的模板文件,然后將數據渲染到模板文件,生成一個渲染后的html文件,該文件會顯示填充的數據

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>戰娃利潤中心指標自動化測試報告</title>
</head>
<body>
    <div style="width:100%;float:left">
                    <table cellspacing="0" cellpadding="4" border="1" align="left">
                        <thead>
                            <tr bgcolor="#F3F3F3">
                                <td style="text-align:center" colspan="9"><b>戰娃利潤中心日報自動檢測</b></td>
                            </tr>
                           <!-- <tr>
                                <td bgcolor="#F3F3F3" style="width:80px"><b>詳細報告:</b></td>
                                <td colspan="8">
                                  <a href="${rooturl}${build.url}robot/report/report.html">點擊查看報告詳情</a>
                                </td>
                            </tr>-->
                            <tr>
                                <td bgcolor="#F3F3F3" style="width:100px"><b>指標預測規則:</b></td>
                                <td colspan="8">
                                 <a href="https://docs.qq.com/sheet/DT1ZBZHdGdXJkVWFL">點擊查看指標預測規則</a>
                                </td>
                            </tr>
                            <!--這里定義的是用例的統計信息-->
                            <tr bgcolor="#F3F3F3">
                                <td><b>用例總數</b></td>
                                <td><b>通過</b></td>
                                <td style="width:60px"><b>不通過</b></td>
                                <td colspan="6"><b>通過率</b></td>
                            </tr>
                            <!--通過2.3的渲染獲取的數據,在這里進行取值填充-->
                            <tr>
                                <td>{{data['total']}}</td>
                                <td><b><span style="color:#66CC00">{{data['pass']}}</span></b></td>
                                <td><b><span style="color:#FF3333">{{data['fail']}}</span></b></td>
                                <td colspan="6">{{data['percent']}}</td>
                            </tr>
                            <!-- 這里定義的是用例的表頭信息-->
                            <tr bgcolor="#F3F3F3">
                                <td colspan="2"><b>Test Name</b></td>
                                <td><b>執行結果</b></td>
                                <td><b>預測上限</b></td>
                                 <td><b>預測下限</b></td>
                                 <td><b>預測值</b></td>
                                 <td><b>實際值</b></td>
                                <td><b>差值(預測-實際)</b></td>
                                <td><b>差值百分比</b></td>
                            </tr>
                        </thead>
                        <tbody>
                        <!--通過2.3的渲染獲取的數據data2,也就是用例信息數據,在這里進行取值填充,由於涉及多個suite,
                        每個suite下有多條case,這里通過兩層循環取每條case的相關信息 -->
                        {% for data in data2 %}
                         <tr>
                                <td colspan="9"><b>{{data['suitename']}}</b></td>
                            </tr>

                        <tr>
                             {% for c2 in data['test'] %}
                                <td colspan="2">{{c2['casename']}}</td>
                                {% if c2['status']=='PASS' %}
                                    <td><b><span style="color:#66CC00">{{c2['status']}}</span></b></td>
                                    {% else %}
                                    <td><b><span style="color:#FF3333" >{{c2['status']}}</span></b></td>
                                {% endif %}
                                <td>{{c2['max']}}</td>
                             <td>{{c2['min']}}</td>
                             {% if c2['casename']=='01 GMV' %}
                                    <td>{{c2['yhat']}}</td>
                                    {% else %}
                                    <td>--</td>
                            {% endif %}
                             <td>{{c2['real']}}</td>
                             {% if c2['casename']=='01 GMV' %}
                                    <td>{{c2['reduce']}}</td>
                                    {% else %}
                                    <td>--</td>
                            {% endif %}
                            {% if c2['casename']=='01 GMV' %}
                                    <td>{{c2['percent']}}</td>
                                    {% else %}
                                    <td>--</td>
                            {% endif %}
                            </tr>
                        {% endfor %}
                        {% endfor %}
                        </tbody>
                    </table>
</body>
</html>
2.5 發送郵件

將上述渲染生成的有數據的html文件作為測試報告進行郵件發送

# !/usr/bin/python
# -*- coding: utf-8 -*-
import smtplib, time, os
from email.mime.text import MIMEText
from email.header import Header
import generate

def send_mail_html(file):
    sender = 'ccc@fulu.com' #發件人
    mail_to =['aa@fulu.com','bb@fulu.com] #收件人
    t = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())  #獲取當前時間
    subject = '戰娃利潤中心指標自動化測試報告' + t  #郵件主題
    smtpserver = 'smtp.qiye.aliyun.com' #發送服務器地址
    username = 'cc@fulu.com' #用戶名
    password = '123456' #密碼
    f = open(file, 'rb')
    mail_body = f.read()
    f.close()


    msg = MIMEText(mail_body, _subtype='html', _charset='utf-8')
    msg['Subject'] = Header(subject, 'utf-8')
    msg['From'] = sender
    msg['To'] = ";".join(mail_to)

    try:
        smtp = smtplib.SMTP()
        smtp.connect(smtpserver)
        smtp.login(username, password)
        smtp.sendmail(sender, mail_to, msg.as_string())
    except:
        print("郵件發送失敗!")
    else:
        print("郵件發送成功!")
    finally:
        smtp.quit()

def result():
    file = 'result.html' #渲染后的html報告文件
    result = {}
    generate.generate_html(result)
    send_mail_html(file)

郵件展示結果
20200904171655

三、回顧整個實現過程

在當初接到該需求的時候,嘗試在網上找相關的實現方案,其中jenkins自帶的RF的插件可以實現報告的解析和郵件發送,第一版我們就是采用該報告模板進行推送
第一版報告,參考該博文https://blog.csdn.net/qq_38317509/article/details/81316940
20200904173031

在需要展示每條用例的具體數據信息的時候,也是嘗試對該模板文件進行修改取值,並查看了插件的源碼實現,發現無法進行這種個性化的數據的取值,源碼只是返回了用例信息、執行狀態和執行時間,以及失敗時候的msg,那能不能通過msg這個關鍵字來做文章呢,也就是把需要查看的數據通過msg打印顯示出來,然而發現只有case失敗的時候才顯示用例,成功的時候不顯示,而且數據以log顯示,查看不是那么清晰
20200904172100

基於上述情況,發現了jinja2這個包,於是就放棄了jenkins的插件,通過自定義報告模板,然后填充數據的方式,這樣靈活度就大大提高了,后續的個性化需求也方便去定制開發了,目前我們還是依賴jenkins進行測試任務的觸發,我們希望將RF這塊也容器化,這塊你們有相關的實踐嗎,歡迎指導~

福祿ICH·質量保證部 福小龍


免責聲明!

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



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