【Python-pytest】 pytest-testreport 生成测试报告
pytest-testreport 安装及使用
pytest-testreport: pytest生成html测试报告的插件,(是基于unittestreport风格的报告扩展而来),报告中会自动收集用例执行的详细日志信息,以及相关错误和输出信息
安装
pip install pytest-testreport
参数
--report :指定报告文件名 --title :指定报告标题 --tester :指定报告中的测试者 --desc :指定报告中的项目描述 --template :指定报告模板样式(1 or 2)
报告样式一
if __name__ == "__main__": """ run debug """ pytest.main([__file__, "--report=_report.html", # 指定报告文件名 '--title=test_report 测试报告', # 指定报告标题 '--tester=Phoenixy', # 指定报告中的测试者 '--desc=报告描述信息', # 指定报告中的项目描述 '--template=1', # 指定报告模板样式(1 or 2) '-W', "ignore:Module already imported:pytest.PytestWarning" ])
报告:
报告样式二
if __name__ == "__main__": """ run debug """ pytest.main([__file__, "--report=_report.html", # 指定报告文件名 '--title=test_report 测试报告', # 指定报告标题 '--tester=Phoenixy', # 指定报告中的测试者 '--desc=报告描述信息', # 指定报告中的项目描述 '--template=2', # 指定报告模板样式(1 or 2) '-W', "ignore:Module already imported:pytest.PytestWarning" ])
报告:
优化pytest_testreport
增加参数 --reportPath=xx 指定报告生成路径
修改安装目录下pytest-testreport.py文件
替换文件内容
# -*- coding: utf-8 -*- import datetime import json import os import time import pytest from jinja2 import Environment, FileSystemLoader test_result = { "title": "", "tester": "", "desc": "", "reportPath": "", "cases": {}, 'rerun': 0, "failed": 0, "passed": 0, "skipped": 0, "error": 0, "start_time": 0, "run_time": 0, "begin_time": "", "all": 0, "testModules": set() } def pytest_make_parametrize_id(config, val, argname): if isinstance(val, dict): return val.get('title') or val.get('desc') def pytest_runtest_logreport(report): report.duration = '{:.6f}'.format(report.duration) test_result['testModules'].add(report.fileName) if report.when == 'call': test_result[report.outcome] += 1 test_result["cases"][report.nodeid] = report elif report.outcome == 'failed': report.outcome = 'error' test_result['error'] += 1 test_result["cases"][report.nodeid] = report elif report.outcome == 'skipped': test_result[report.outcome] += 1 test_result["cases"][report.nodeid] = report def pytest_sessionstart(session): start_ts = datetime.datetime.now() test_result["start_time"] = start_ts.timestamp() test_result["begin_time"] = start_ts.strftime("%Y-%m-%d %H:%M:%S") def handle_history_data(report_dir, test_result): """ 处理历史数据 :return: """ try: with open(os.path.join(report_dir, 'history.json'), 'r', encoding='utf-8') as f: history = json.load(f) except: history = [] history.append({'success': test_result['passed'], 'all': test_result['all'], 'fail': test_result['failed'], 'skip': test_result['skipped'], 'error': test_result['error'], 'runtime': test_result['run_time'], 'begin_time': test_result['begin_time'], 'pass_rate': test_result['pass_rate'], }) with open(os.path.join(report_dir, 'history.json'), 'w', encoding='utf-8') as f: json.dump(history, f, ensure_ascii=True) return history def pytest_sessionfinish(session): """在整个测试运行完成之后调用的钩子函数,可以在此处生成测试报告""" report2 = session.config.getoption('--report') reportPath = session.config.getoption('--reportPath') if report2: test_result['reportPath'] = reportPath or "reports" test_result['title'] = session.config.getoption('--title') or '测试报告' test_result['tester'] = session.config.getoption('--tester') or '小测试' test_result['desc'] = session.config.getoption('--desc') or '无' templates_name = session.config.getoption('--template') or '1' name = report2 else: return if not name.endswith('.html'): file_name = time.strftime("%Y-%m-%d_%H_%M_%S") + name + '.html' else: file_name = time.strftime("%Y-%m-%d_%H_%M_%S") + name if os.path.isdir(test_result['reportPath']): pass else: os.mkdir(test_result['reportPath']) file_name = os.path.join(test_result['reportPath'], file_name) test_result["run_time"] = '{:.6f} S'.format(time.time() - test_result["start_time"]) test_result['all'] = len(test_result['cases']) if test_result['all'] != 0: test_result['pass_rate'] = '{:.2f}'.format(test_result['passed'] / test_result['all'] * 100) else: test_result['pass_rate'] = 0 # 保存历史数据 test_result['history'] = handle_history_data(test_result['reportPath'], test_result) # 渲染报告 template_path = os.path.join(os.path.dirname(__file__), './templates') env = Environment(loader=FileSystemLoader(template_path)) if templates_name == '2': template = env.get_template('templates2.html') else: template = env.get_template('templates.html') report = template.render(test_result) # print(file_name) with open(file_name, 'wb') as f: f.write(report.encode('utf8')) @pytest.hookimpl(tryfirst=True, hookwrapper=True) def pytest_runtest_makereport(item, call): outcome = yield report = outcome.get_result() fixture_extras = getattr(item.config, "extras", []) plugin_extras = getattr(report, "extra", []) report.extra = fixture_extras + plugin_extras report.fileName = item.location[0] if hasattr(item, 'callspec'): report.desc = item.callspec.id or item._obj.__doc__ else: report.desc = item._obj.__doc__ report.method = item.location[2].split('[')[0] def pytest_addoption(parser): group = parser.getgroup("testreport") group.addoption( "--reportPath", action="store", metavar="path", default=None, help="create html report file at given path.", ) group.addoption( "--report", action="store", metavar="path", default=None, help="create html report file at given path.", ) group.addoption( "--title", action="store", metavar="path", default=None, help="pytest-testreport Generate a title of the repor", ) group.addoption( "--tester", action="store", metavar="path", default=None, help="pytest-testreport Generate a tester of the report", ) group.addoption( "--desc", action="store", metavar="path", default=None, help="pytest-testreport Generate a description of the report", ) group.addoption( "--template", action="store", metavar="path", default=None, help="pytest-testreport Generate a template of the report", )
示例:
Tips: "--reportPath=../reports" 使用此参数时需要 替换依赖包中的pytest-testreport.py文件(即上面增加参数的步骤),否则默认在启动文件统计目录创建report文件夹
if __name__ == "__main__": """ run debug """ pytest.main([__file__, "--reportPath=../reports", # 指定报告生成路径 Tips:当前文件的上一级目录同级目录reports文件夹下 "--report=_report.html", # 指定报告文件名 '--title=test_report 测试报告', # 指定报告标题 '--tester=Phoenixy', # 指定报告中的测试者 '--desc=报告描述信息', # 指定报告中的项目描述 '--template=2', # 指定报告模板样式(1 or 2) '-W', "ignore:Module already imported:pytest.PytestWarning" ])
结果
可能会与pytest-html存在冲突,若冲突需要卸载pytest-html
源码地址: https://gitee.com/lemon-test-official/pytest-testreport
-------------------------------------------------------------------------------------
如果万事开头难 那请结局一定圆满 @ Phoenixy
-------------------------------------------------------------------------------------