快速實現(xiàn)自定義的測試報告
一、背景
RF的結(jié)果報告可以方便我們查看每一條用例集、用例的執(zhí)行結(jié)果統(tǒng)計,但是有的項目涉及到一些數(shù)據(jù)的比對,希望能夠直觀到看到數(shù)據(jù),原生的測試報告就無法滿足這個需求了。
原生的報告

項目需求報告格式

二、解決方案
2.1 流程圖

解析output.xml,將用例的相關(guān)信息和執(zhí)行結(jié)果獲取
通過API和數(shù)據(jù)庫獲取需要展示的數(shù)據(jù)
將上述兩步的數(shù)據(jù)封裝到一個數(shù)據(jù)列表中,方便后面進行模板渲染
根據(jù)需求畫HTML的報告模板
對模板進行數(shù)據(jù)填充渲染,生成報告文件
郵件發(fā)送報告
2.2 output.xml解析
測試用例相關(guān)的信息和運行結(jié)果,我們可以通過解析RF的output.xml文件來進行獲取
2.2.1獲取用例運行情況的統(tǒng)計

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節(jié)點個數(shù)
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"))#失敗用例數(shù)
d['pass'] = int(statlist[i].getAttribute("pass"))#成功用例數(shù)
d['total'] = d['fail']+d['pass']#用例總數(shù)
d['percent'] = ('{:.2%}'.format(d['pass'] / d['total']))#用例百分比
list.append(d)
return list
2.2.2 獲取用例信息
用例的組織結(jié)構(gòu)

獲取用例信息和執(zhí)行結(jié)果
用例結(jié)構(gòu)是多個suite,每個suite下有4條case

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下的子節(jié)點
def getcase():
casedict = {}
testlist2 = []
for elem in tree3.iterfind('suite/suite'):
a = elem.attrib
suitedict = {}
testlist2.append(suitedict) #每一個用例集合存入列表
testlist = []
suitename = a['name']#獲取用例結(jié)合的名字
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'] #獲取每條用例的執(zhí)行結(jié)果
casedict['casename'] = casename #用例名字存入字典
casedict['status'] = status #用例執(zhí)行結(jié)果存入字典
testlist.append(casedict) #每一條用例的名字和執(zhí)行結(jié)果作為字典存入列表
casedict = {}
suitedict['suitename']=suitename
suitedict['test']=testlist
return testlist2 #最終返回的就是[{'suitename': 'xxx', 'test': [{'casename': '01 xxx', 'status': 'PASS'}, {'casename': '02 xxx', 'status': 'PASS'}
2.3 數(shù)據(jù)填充
通過前面獲取的獲取,填充到j(luò)inja2的模板中,會生成另外一個有數(shù)據(jù)的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的用例統(tǒng)計數(shù)據(jù)
data2=parsexml.getcase()#獲取測試用例信息和執(zhí)行結(jié)果
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模板的原理就是,通過先創(chuàng)建一個html的模板文件,然后將數(shù)據(jù)渲染到模板文件,生成一個渲染后的html文件,該文件會顯示填充的數(shù)據(jù)
<html lang="en">
<head>
<meta charset="utf-8">
<title>戰(zhàn)娃利潤中心指標(biāo)自動化測試報告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>戰(zhàn)娃利潤中心日報自動檢測b>td>
tr>
<tr>
<td bgcolor="#F3F3F3" style="width:100px"><b>指標(biāo)預(yù)測規(guī)則:b>td>
<td colspan="8"><a href="https://docs.qq.com/sheet/DT1ZBZHdGdXJkVWFL">點擊查看指標(biāo)預(yù)測規(guī)則a>td>
tr>
<tr bgcolor="#F3F3F3">
<td><b>用例總數(shù)b>td>
<td><b>通過b>td>
<td style="width:60px"><b>不通過b>td>
<td colspan="6"><b>通過率b>td>
tr>
<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 Nameb>td>
<td><b>執(zhí)行結(jié)果b>td>
<td><b>預(yù)測上限b>td>
<td><b>預(yù)測下限b>td>
<td><b>預(yù)測值b>td>
<td><b>實際值b>td>
<td><b>差值(預(yù)測-實際)b>td>
<td><b>差值百分比b>td>
tr>
thead>
<tbody>
{% 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 發(fā)送郵件
將上述渲染生成的有數(shù)據(jù)的html文件作為測試報告進行郵件發(fā)送
# !/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 = '[email protected]' #發(fā)件人
mail_to =['[email protected]','[email protected]] #收件人
t = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) #獲取當(dāng)前時間
subject = '戰(zhàn)娃利潤中心指標(biāo)自動化測試報告' + t #郵件主題
smtpserver = 'smtp.qiye.aliyun.com' #發(fā)送服務(wù)器地址
username = '[email protected]' #用戶名
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("郵件發(fā)送失敗!")
else:
print("郵件發(fā)送成功!")
finally:
smtp.quit()
def result():
file = 'result.html' #渲染后的html報告文件
result = {}
generate.generate_html(result)
send_mail_html(file)
郵件展示結(jié)果

三、回顧整個實現(xiàn)過程
在當(dāng)初接到該需求的時候,嘗試在網(wǎng)上找相關(guān)的實現(xiàn)方案,其中jenkins自帶的RF的插件可以實現(xiàn)報告的解析和郵件發(fā)送,第一版我們就是采用該報告模板進行推送
第一版報告,參考該博文https://blog.csdn.net/qq_38317509/article/details/81316940

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

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

