自动化测试报告 html模板,PyTestReport 自动化测试报告框架
PyTestReport
一個由HTMLTestRunner項目為靈感,并基于HTMLTestRunner進行二次開發的一個項目。主要在 API 調用、報告樣式、擴展性等方面進行了增強。
點擊查看HTMLTestRunner的官網。HTMLTestRunner是基于 Python 單元測試官方實現的TextTestResult為參考,實現了對應的HTMLTestResult版本。
安裝與使用
安裝
通過 pip 安裝 pip installPyTestReport
通過安裝包
可通過發布的安裝包進行安裝,具體安裝包可在 dist 目錄查找。
pip installPyTestReport-0.1.X-py3-none-any.whl
通過源碼(最新版本) pip installgit+https://github.com/five3/PyTestReport.git
或者
git clone https://github.com/five3/PyTestReport.git
cdPyTestReport
python setup.py build
python setup.py install
使用
PyTestReport 可用通過多種方式運行,分別如下:
單元測試 (unittest, pytest)
lib 庫引入
命令行
REST API
樣例說明
單元測試樣例 (unittest) import unittest
import pytestreport
class MyTest(unittest.TestCase):
def testTrue(self):
self.assertTrue(True)
if __name__ == '__main__':
pytestreport.main(verbosity=2)
以這種方式執行之后,默認會在當前文件夾下生成一個PyTestReport.html日志文件,且這個文件名和樣式模板都不可以重新指定的。
注意:這種方式執行時,如果使用 Pycharm 等 IDE,確保不是以 IDE 的內建單元測試框架來執行的;或者直接通過命令行來執行。
import unittest
from pytestreport import TestRunner
class MyTest(unittest.TestCase):
def testTrue(self):
self.assertTrue(True)
if __name__ == '__main__':
suite = unittest.TestSuite()
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(MyTest))
with open(r'/path/to/report.html', 'wb') as fp:
runner = TestRunner(fp, title='測試標題', description='測試描述', verbosity=2)
runner.run(suite)
這種方式適合批量加載和執行測試用例,從測試文件的外部來導入測試用例并執行。這里可以指定具體的結果文件路徑和測試標識等信息。
這里使用的是默認模板主題,如果想要使用其它模板主題,可以通過制定模板的主題文件來實現。比如:使用遺留模板的方式如下所示。
from pytestreport import TestRunner
...
runner = TestRunner(fp, title='測試標題', description='測試描述', verbosity=2, theme='legency')
單元測試樣例(pytest)
對于 pytest 框架,收集其測試結果信息是通過 pytest 插件形式實現的。使用之前只要確保正常安裝了 PyTestReport 即可。具體使用方式如下:
import pytest
def testTrue():
assert True
def testFalse():
assert False
def testError():
1 / 0
@pytest.mark.skip(reason="misunderstood the API")
def testSkip():
assert 1 == 1
@pytest.mark.xfail(reason="Xpass")
def testXPass():
assert True
@pytest.mark.xfail(reason="Xfail")
def testXFail():
assert False
if __name__ == '__main__':
pytest.main(["-s", "pytest_Demo.py", "--pytest_report", "Pytest_Report.html"])
需要注意的是,pytest 框架想要使用本測試報告框架,在調用時需要帶上--pytest_report參數,并指定一個報告的文件路徑即可。當然你也可以同時指定一個非默認主題。比如:
import pytest
if __name__ == '__main__':
pytest.main(["-s", "pytest_Demo.py", "--pytest_report", "Pytest_Report.html",
"--pytest_title", "report title", "--pytest_desc", "report desc",
"--pytest_theme", "new_theme"])
另外,你也可以通過命令行的方式來啟動 pytest 執行單元測試。比如:
pytest -s pytest_Demo.py --pytest_report Pytest_Report.html --pytest_theme new_theme
API 庫引入樣例 from pytestreport.api import make_report
data = {
"generator": "PyTestReport 0.1.4",
"title": "默認主題",
"description": "默認主題描述",
"report_summary": {
"start_time": "2019-05-12 23:07:49",
"duration": "0:00:00.002000",
"suite_count": 1,
"status": {
"pass": 1,
"fail": 0,
"error": 0,
"skip": 0,
"count": 1
}
},
"report_detail": {
"tests": [
{
"summary": {
"desc": "utDemo.UTestPass",
"count": 1,
"pass": 1,
"fail": 0,
"error": 0,
"skip": 0,
"cid": "testclass1",
"status": "pass"
},
"detail": [
{
"has_output": False,
"tid": "testpass.1.1",
"desc": "testTrue",
"output": "",
"status": "pass",
"status_code": 0
}
]
}
],
"count": "1",
"pass": "1",
"fail": "0",
"error": "0",
"skip": "0"
}
}
with open('API_Report.html', 'wb') as fp:
make_report(fp, data)
# will be create API_Report.html file at current directory.
同樣的,你也可以指定特定的主題或者樣式。比如:
...
with open('API_Report.html', 'wb') as fp:
make_report(fp, data, theme='new_theme', stylesheet='new_stylesheet_2.css')
命令行樣例
命令行樣式,以 data 的 json 文件為參數,同時可選的參數有主題,樣式、js 等。
PyTestReport.shell /path/to/data/file.json [reportfile theme htmltemplate stylesheet javascript]
# will be create html report at current directory, the content of data.json should same as the data object in API sample.
實際運行時,需要把符合規范的測試結果數據存放到 data.json 文件中。比如:當前 data.json 的數據已與 API 樣例中的 data 數據等同。
PyTestReport.shell data.json output.html
REST API 樣例 暫未支持
開發相關
PyTestReport對原項目進行了改進,使用了 Jinjia2 作為模板引擎。且 CSS、JS、HTML 文件都進行了分離,所以可以通過改變單獨或者全部文件來達到修改模板的目的。當然這里的修改通常指新增一個文件,而在執行時只要指定使用該新文件即可。
目前默認保留了 2 個主題的模板:一個是HTMLTestRunner原來的模板樣式 (legency),一個是依據原模板進行 UI 優化的模板樣式 (default)。
另外,后期會收集和添加其它更豐富的模板,也歡迎大家來踴躍的為該項目添加新模板和樣式。
如何更新樣式
樣式文件被存放在static/css/目錄下,默認保留了 2 個樣式:default.css, legency.css。想要修改樣式的方式 2 兩種:
直接修改當前主題對應的 css 文件
復制當前主題的 css 文件,在進行修改(推薦)
第一種方式修改之后重新執行單元測試會直接生效。第二種方式則需要修改下實例化PyTestReport.TestRunner的 style 參數。比如:
from pytestreport import TestRunner
...
runner = TestRunner(fp, title='測試標題', description='測試描述', verbosity=2, stylesheet='new_style.css')
如何更新 JS
JS 文件被存放在static/js/目錄下,默認保留了 2 個 JS:default.js, legency.js。修改 JS 的方式和修改樣式一樣有 2 種,同樣我們推薦復制并修改新 JS 文件的方式。指定新 JS 文件的使用方式如下:
from pytestreport import TestRunner
...
runner = TestRunner(fp, title='測試標題', description='測試描述', verbosity=2, javaScript='new_js.js')
如何更新模板
HTML 的模板被存放在templates目錄下,默認保留了 2 個模板:default.html, legency.html。
如果你選擇修改模板,那么一般情況下你可能同時也需要修改 CSS 或 JS 文件。所以我們更推薦的方式是直接新增一個主題(包括 html、css、js),并且在主題功能完善之后發送一個 pull request,貢獻到本項目中提供給更多的人使用!
新模板的使用方式如下:
from pytestreport import TestRunner
...
runner = TestRunner(fp, title='測試標題', description='測試描述', verbosity=2,
htmltemplate='new_theme.html', stylesheet='new_theme.css', javascript='new_theme.js')
或者
from pytestreport import TestRunner
...
runner = TestRunner(fp, title='測試標題', description='測試描述', verbosity=2, theme='new_theme')
這里需要注意的是,如果新模板需要引用第三方庫(js、css),請優先使用 CDN 鏈接而非本地靜態文件。
Jinjia2 模板傳入數據格式
使用 Jinjia2 模板來渲染 HTML 報告時,會傳入相應的測試結果集的數據對象。這里列出一個簡要的樣例及說明,為希望添加新主題的同學提供參考。
{"generator":"PyTestReport 0.1.3","title":"默認主題",#本次單元測試的主標題"description":"默認主題描述",#本次單元測試的描述"stylesheet":"\nbody { font-family: verdana, arial, helvetica, sans-serif; font-size: 80%; }\ntable { font-size: 100%; }\npre { }\n\n/* -- heading ---------------------------------------------------------------------- */\n.heading {\nmargin: 10px;\n}\n.heading .attribute {\nmargin-top: 1ex;\nmargin-bottom: 0;\n}\n\n/* -- css div popup ------------------------------------------------------------------------ */\na.popup_link {\n}\na.popup_link:hover {\ncolor: red;\n}\n.popup_window {\ndisplay: none;\nposition: relative;\nleft: 0px;\ntop: 0px;\n/*border: solid #627173 1px; */\npadding: 10px;\nbackground-color: #E6E6D6;\nfont-family:\"Lucida Console\",\"Courier New\", Courier, monospace;\ntext-align: left;\nfont-size: 8pt;\nwidth: 500px;\n}\n\n/* -- report ------------------------------------------------------------------------ */\n#show_detail_line {\nmargin-top: 3ex;\nmargin-bottom: 1ex;\n}\n#result_table {\nwidth: 80%;\nborder-collapse: collapse;\nborder: 1px solid #4682B4;\n}\n#header_row {\nfont-weight: bold;\ncolor: white;\nbackground-color: #4682B4;\n}\n#result_table td {\nborder: 1px solid #a09d9d;\npadding: 2px;\n}\n#total_row { font-weight: bold; }\n.passClass { background-color: #00ff3733; }\n.failClass { background-color: #f5091f3d; }\n.errorClass { background-color: #0662bb2e; }\n.skipClass { background-color: #40403f38; }\n.passCase { color: #28a745; }\n.failCase { color: #dc3545; font-weight: bold; }\n.errorCase { color: #0c6cff; font-weight: bold; }\n.skipCase { color: #40403f; }\n.hiddenRow { display: none; }\n.testcase { margin-left: 2em; }\n\n/* -- ending ---------------------------------------------------------------------- */\n#ending {\nmin-height: 30px;\n}\n","javascript":"\noutput_list = Array();\n/* level - 0:Summary; 1:Failed; 2:Skip; 3:All */\n\nfunction showCase(level) {\ntrs = document.getElementsByTagName(\"tr\");\nfor (var i = 0; i < trs.length; i++) {\ntr = trs[i];\nid = tr.id;\n\nif (level === 0 && tr.getAttribute('type') === 'case') {\ntr.className = 'hiddenRow';\n} else if (level === 1) {\nif (id.substr(0,2) === 'ft') {\ntr.className = '';\n} else if (tr.getAttribute('type') === 'case') {\ntr.className = 'hiddenRow';\n}\n} else if (level === 2) {\nif (id.substr(0,2) === 'et') {\ntr.className = '';\n} else if (tr.getAttribute('type') === 'case') {\ntr.className = 'hiddenRow';\n}\n} else if (level === 3) {\nif (id.substr(0,2) === 'st') {\ntr.className = '';\n} else if (tr.getAttribute('type') === 'case') {\ntr.className = 'hiddenRow';\n}\n} else if (level === 4 && tr.getAttribute('type') === 'case') {\ntr.className = '';\n}\n}\n}\n\nfunction showClassDetail(cid, count) {\nvar tr_list = document.querySelectorAll('tr[cid='+cid+']');\nvar toHide = 1;\n\nfor (var i = 0; i < count; i++) {\nif (tr_list[i].className) {\ntoHide = 0;\n}\n}\nfor (var i = 0; i < count; i++) {\nif (toHide) {\ntr_list[i].className = 'hiddenRow';\n} else {\ntr_list[i].className = '';\n}\n}\n}\n\nfunction showTestDetail(div_id){\nvar details_div = document.getElementById(div_id)\nvar displayState = details_div.style.display\n// alert(displayState)\nif (displayState != 'block' ) {\ndisplayState = 'block'\ndetails_div.style.display = 'block'\n}\nelse {\ndetails_div.style.display = 'none'\n}\n}\nfunction html_escape(s) {\ns = s.replace(/&/g,'&');\ns = s.replace(//g,'>');\nreturn s;\n}\n\n\n","report_summary":{#報告總體概要數據"start_time":"2019-05-12 23:07:49","duration":"0:00:00.002000","suite_count":1,"status":{"pass":1,"fail":0,"error":0,"skip":0,"count":1}},"report_detail":{#報告詳情數據"tests":[{"summary":{#測試用例類的概要數據"desc":"utDemo.UTestPass",#測試用例類的名稱"count":1,"pass":1,"fail":0,"error":0,"skip":0,"cid":"testclass1",#唯一標識測試用例類的id:testclass1--表示排序后的第1個測試用例類"status":"pass"},"detail":[#測試用例的詳情{"has_output":false,#標識該測試用例是否有輸出內容,通常PASS是沒有輸出內容的。"tid":"testpass.1.1",#唯一標識測試用例的id,格式為:test{測試結果狀態}.{所屬測試用例類的序號}.{當前測試用例的序號}"desc":"testTrue",#測試用例名稱"output":"",#輸出內容,如果該測試用例有輸出的話"status":"pass","status_code":0#測試結果狀態碼,0為PASS,1為FAIL,2為ERROR,3為SKIP}]}],"count":"1","pass":"1","fail":"0","error":"0","skip":"0"}}
另外,在你進行新主題模板調試時,也可以通過如下的方式獲取真實的模板數據和渲染之后的 html 內容。
import json
from pytestreport import TestRunner
...
runner = TestRunner(fp, title='默認主題', description='默認主題描述', verbosity=2)
result = runner.run(suite)
print(json.dumps(result.pytestreport_data, ensure_ascii=False, indent=2)) # 傳入Jinjia2模板的數據對象print(result.pytestreport_html) # 渲染成功之后的HTML內容
模板展示
默認主題
合作
對此項目感興趣的朋友,歡迎為加入我們的行列,貢獻你的一份力量。你可以:
添加新的測試報告模板
添加新的測試報告樣式
開發并擴展可用功能
提出需求和寶貴意見
另外使用過程中如果有任何問題或疑惑,你可以:
在 github 上給本項目提 ISSUE
發送郵件至 five3@163.com
總結
以上是生活随笔為你收集整理的自动化测试报告 html模板,PyTestReport 自动化测试报告框架的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 炉石android更新日志,炉石传说每逢
- 下一篇: html 背景设为透明背景图片,Thre