项目目录
一.实例生成报告(和python2.7配合使用无法生成报告)
-test_pytest_html_one.py
-import pytest
-
-
-def login(username,password):
- """ 模拟登录 """
- user = "linux超"
- pwd = "linux超哥"
-
- if user == username and pwd == password:
- return {"code":1001,"msg":"登录成功","data":None}
- else:
- return {"code":1000,"msg":"用户名或密码错误","data":None}
-
-
-test_data = [
- # 测试数据
- {
- "case": "用户名正确, 密码正确",
- "user": "xxx",
- "pwd": "xxx",
- "expected": {"code": 1001, "msg": "登录成功", "data": None}
- },
- {
- "case": "用户名正确, 密码为空",
- "user": "xxx",
- "pwd": "",
- "expected": {"code": 1000, "msg": "用户名或密码错误", "data": None}
- },
- {
- "case": "用户名为空, 密码正确",
- "user": "",
- "pwd": "xxx",
- "expected": {"code": 1000, "msg": "用户名或密码错误", "data": None}
- },
- {
- "case": "用户名错误, 密码错误",
- "user": "x",
- "pwd": "x",
- "expected": {"code": 1000, "msg": "用户名或密码错误", "data": None}
- }
-]
-
-
-# 修改Results:改变输出结果
-ids = [
- "测试:{}->[用户名:{}-密码:{}-预期:{}]".
- format(data["case"], data["user"], data["pwd"], data["expected"]) for data in test_data
-]
-
-
-class TestLogin(object):
- # 添加ids参数
- @pytest.mark.parametrize("data",test_data,ids=ids)
- def test_login(self,data):
- result = login(data["user"],data["pwd"])
- assert result == data["expected"]
-
-
-if __name__ == "__main__":
- pytest.main(['-sv',"G:\\pytestbasics\\test_pytest_html_case","--html", "report.html"])
-
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
1.修改Environment
1.1.在Environment中删除Java_Home,添加测试接口地址该如何添加?
1.2.在项目的根目录新键conftest.py文件。
-conftest.py
-def pytest_configure(config):
- # 添加接口地址与项目名称
- config._metadata["项目名称"] = "xxxxxx"
- config._metadata['接口地址'] = 'xxxxxx'
- # 删除Java_Home
- config._metadata.pop("JAVA_HOME")
-
- 1
- 2
- 3
- 4
- 5
- 6
2.修改Summary
2.1.原始的报告中Summary部分只显示了测试用例数及用例执行时间,那么如果想在这个位置添加测试人员等一些信息该如何实现?
conftest.py
-@pytest.mark.optionalhook
-def pytest_html_results_summary(prefix):
- prefix.extend([html.p("所属部门: xxx")])
- prefix.extend([html.p("测试人员: xxx")])
-
- 1
- 2
- 3
- 4
3.修改Results:Results主要展示的是测试结果信息,比如Test列显示的内容很长,它主要是测试用例所在的路径及测试类,测试用例及测试数据拼接而成的,可读性很差。所以改成显:测试+用例名称[user:用户名-pwd:密码] 。
4.优化Test
4.1.原始的测试报告的Test列表的信息是怎么生成的。找到pytest-html插件的安装位置,打开plugin.py文件。
class TestResult:
- def __init__(self, outcome, report, logfile, config):
- self.test_id = report.nodeid
-
- if getattr(report, "when", "call") != "call":
- self.test_id = "::".join([report.nodeid, report.when])
- self.time = getattr(report, "duration", 0.0)
- self.outcome = outcome
-
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
4.2.第3行,5行,就是报告中Test信息的来源,test_pytest_html_one.py::TestLogin::test_login[data0] 这样一条信息,实际是用例的nodeid,而【data0】是测试用例参数化时的每个参数。
其中参数化方法@pytest.mark.parametrize(“data”, test_data)的参数ids的作用主要就是用来标记测试用例(第9篇文章),增加测试用例执行后输出信息的可读性,因此可以使用这个参数来改变【data0】,让它显测试数据。
conftest.py
-# 改变输出结果
-ids = [
- "测试:{}->[用户名:{}-密码:{}-预期:{}]".
- format(data["case"], data["user"], data["pwd"], data["expected"]) for data in test_data
-]
-
-class TestLogin(object):
- # 添加ids参数
- @pytest.mark.parametrize("data", test_data, ids=ids)
- def test_login(self, data):
- result = login(data["user"], data["pwd"])
- assert result == data["expected"]
-
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
4.3.中文部分显示的都是乱码。
4.4.解决中文乱码
-conftest.py
-import pytest
-from py._xmlgen import html
-
-@pytest.mark.hookwrapper
-def pytest_runtest_makereport(item):
- outcome = yield
- report = outcome.get_result()
- getattr(report, 'extra', [])
- report.nodeid = report.nodeid.encode("utf-8").decode("unicode_escape") # 解决乱码
-
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
5.删除多余部分
5.1.要删除前面多余的部分,查看html报告的页面元素属性。
5.2.使用js代码改变这个元素的innerText。
// 找到Test列中所有的表格元素
-var test_name = document.getElementBysClassName("col-name");
-// 修改第1个表格的innerText属性
-test_name[0].innerText = test_name[0].innerText.split("\[")[1].split(["\]")[0]; // 以[符号分割一次,再以]分割一次,得到目标字符串
-
- 1
- 2
- 3
- 4
5.3.前面的代码只能修改一个表格,如果要修改多个表格只能使用循环。
var case_name_td = document.getElementsByClassName("col-name")
- for(var i = 0; i < case_name_td.length; i++)
- try{
- case_name_td[i].innerText = case_name_td[i].innerText.split("\[")[1].split("\]")[0];
- }
- catch(err){
- // 如果表格中没有[]会抛异常,如果抛异常我就显示null,如果你想显示别的东西自己改吧,因为通常只要我们使用参数化就有[]显示
- case_name_td[i].innerText = "null";
- }
-
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
5.4.js代码写好了但是要放在哪里?通过查看报告的html源码发现在html代码的开头引入了这样一些代码。
5.5.在pytest-html插件的源码中发现插件的resource目录下有main.js文件,里面的代码就是上述html代码中的js脚本。
5.6.在main.js中确实存在init()方法,因此把编写的js代码放到init()方法内部。
-function init () {
- reset_sort_headers();
-
- add_collapse();
-
- show_filters();
-
- toggle_sort_states(find('.initial-sort'));
-
- find_all('.sortable').forEach(function(elem) {
- elem.addEventListener("click",
- function(event) {
- sort_column(elem);
- }, false)
- });
- // 修改用例报告显示的用例名称
- var case_name_td = document.getElementsByClassName("col-name")
- for(var i = 0; i < case_name_td.length; i++)
- try{
- case_name_td[i].innerText = case_name_td[i].innerText.split("\[")[1].split("\]")[0];
- }
- catch(err){
- // 如果表格中没有[]会抛异常,如果抛异常我就显示null,如果你想显示别的东西自己改吧,因为通常只要我们使用参数化就有[]显示
- case_name_td[i].innerText = "null";
- }
-};
-
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
6.删除Links
conftest.py
@pytest.mark.optionalhook
-def pytest_html_results_table_header(cells):
- cells.pop(-1) # 删除link列
-
-@pytest.mark.optionalhook
-def pytest_html_results_table_row(report, cells):
- cells.pop(-1) # 删除link列
-
- 1
- 2
- 3
- 4
- 5
- 6
- 7
7.增加失败截图与用例描述
-https://blog.csdn.net/hyq413950612/article/details/123743418?spm=1001.2014.3001.5502
-https://blog.csdn.net/hyq413950612/article/details/123790898
-二.完整的conftest.py文件
-import pytest
-from selenium import webdriver
-from py._xmlgen import html
-
-_driver = None
-# 测试失败时添加截图和测试用例描述(用例的注释信息)
-
-@pytest.mark.hookwrapper
-def pytest_runtest_makereport(item):
- """当测试失败的时候,自动截图,展示到html报告中"""
- pytest_html = item.config.pluginmanager.getplugin('html')
- outcome = yield
- report = outcome.get_result()
- extra = getattr(report, 'extra', [])
-
- if report.when == 'call' or report.when == "setup":
- xfail = hasattr(report, 'wasxfail')
- if (report.skipped and xfail) or (report.failed and not xfail):
- file_name = report.nodeid.replace("::", "_")+".png"
- screen_img = _capture_screenshot()
- if file_name:
- html = '<div><img src="data:image/png;base64,%s" alt="screenshot" style="width:600px;height:300px;" ' \
- 'οnclick="window.open(this.src)" align="right"/></div>' % screen_img
- extra.append(pytest_html.extras.html(html))
- report.extra = extra
-
- extra.append(pytest_html.extras.text('some string', name='Different title'))
- report.description = str(item.function.__doc__)
- report.nodeid = report.nodeid.encode("utf-8").decode("unicode_escape") # 解决乱码
-
-
-
-def _capture_screenshot():
- '''截图保存为base64'''
- return _driver.get_screenshot_as_base64()
-
-
-def pytest_configure(config):
- # 添加接口地址与项目名称
- config._metadata["项目名称"] = "Linux超博客园自动化测试项目v1.0"
- config._metadata['接口地址'] = 'https://www.cnblogs.com/linuxchao/'
- # 删除Java_Home
- config._metadata.pop("JAVA_HOME")
-
-
-@pytest.mark.optionalhook
-def pytest_html_results_summary(prefix):
- prefix.extend([html.p("所属部门: xx测试中心")])
- prefix.extend([html.p("测试人员: Linux超")])
-
-
-@pytest.mark.optionalhook
-def pytest_html_results_table_header(cells):
- cells.insert(1, html.th('Description'))
- cells.pop(-1) # 删除link列
-
-
-@pytest.mark.optionalhook
-def pytest_html_results_table_row(report, cells):
- cells.insert(1, html.td(report.description))
- cells.pop(-1) # 删除link列
-
-
-def pytest_configure(config):
- # 添加接口地址与项目名称
- config._metadata["项目名称"] = "xxxxx"
- config._metadata['接口地址'] = 'xxxxx'
- # 删除Java_Home
- config._metadata.pop("JAVA_HOME")
-
-
-@pytest.fixture(scope='module') #或者改成session
-def driver():
- global _driver
- _driver = webdriver.Chrome()
-
- yield _driver
- _driver.quit()
-
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
三.汉化报告
1.修改plugin.py文件主要用来生成测试报告的html代码。
# if len(log) == 0:
-# log = html.div(class_='empty log')
-# log.append('No log output captured.')
-if len(log) == 0:
- log = html.div(class_='empty log')
- log.append('未捕获到日志')
-additional_html.append(log)
-
- 1
- 2
- 3
- 4
- 5
- 6
- 7
# head = html.head(
-# html.meta(charset='utf-8'),
-# html.title('Test Report'),
-# html_css)
-head = html.head(
- html.meta(charset='utf-8'),
- html.title('测试报告'),
- html_css)
-
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
# outcomes = [Outcome('passed', self.passed),
-# Outcome('skipped', self.skipped),
-# Outcome('failed', self.failed),
-# Outcome('error', self.errors, label='errors'),
-# Outcome('xfailed', self.xfailed,
-# label='expected failures'),
-# Outcome('xpassed', self.xpassed,
-# label='unexpected passes')]
-outcomes = [Outcome('passed', self.passed, label="通过"),
- Outcome('skipped', self.skipped, label="跳过"),
- Outcome('failed', self.failed, label="失败"),
- Outcome('error', self.errors, label='错误'),
- Outcome('xfailed', self.xfailed,
- label='预期失败'),
- Outcome('xpassed', self.xpassed,
- label='预期通过')]
-
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
# if self.rerun is not None:
-# outcomes.append(Outcome('rerun', self.rerun))
-if self.rerun is not None:
- outcomes.append(Outcome('重跑', self.rerun))
-
-# summary = [html.p(
-# '{0} tests ran in {1:.2f} seconds. '.format(
-# numtests, suite_time_delta)),
-# html.p('sfsf',
-# class_='filter',
-# hidden='true')]
-summary = [html.p(
- '执行了{0}个测试用例, 历时:{1:.2f}秒 . '.format(
- numtests, suite_time_delta)),
- html.p('(取消)勾选复选框, 以便筛选测试结果',
- class_='filter',
- hidden='true')]
-
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
# cells = [
-# html.th('Result',
-# class_='sortable result initial-sort',
-# col='result'),
-# html.th('Test', class_='sortable', col='name'),
-# html.th('Duration', class_='sortable numeric', col='duration'),
-# html.th('Links')]
-cells = [
- html.th('通过/失败',
- class_='sortable result initial-sort',
- col='result'),
- html.th('用例', class_='sortable', col='name'),
- html.th('耗时', class_='sortable numeric', col='duration'),
- html.th('链接')]
-
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
# results = [html.h2('Results'), html.table([html.thead(
-# html.tr(cells),
-# html.tr([
-# html.th('No results found. Try to check the filters',
-# colspan=len(cells))],
-# id='not-found-message', hidden='true'),
-# id='results-table-head'),
-# self.test_logs], id='results-table')]
-results = [html.h2('测试结果'), html.table([html.thead(
- html.tr(cells),
- html.tr([
- html.th('无测试结果, 试着选择其他测试结果条件',
- colspan=len(cells))],
- id='not-found-message', hidden='true'),
- id='results-table-head'),
- self.test_logs], id='results-table')]
-
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
#html.p('Report generated on {0} at {1} by '.format(
-html.p('生成报告时间{0} {1} Pytest-Html版本:'.format(
-
- 1
- 2
# body.extend([html.h2('Summary')] + summary_prefix
-# + summary + summary_postfix)
-body.extend([html.h2('用例统计')] + summary_prefix
- + summary + summary_postfix)
-
- 1
- 2
- 3
- 4
# environment = [html.h2('Environment')]
-environment = [html.h2('测试环境')]
-
- 1
- 2
2.修改main.js文件。
-/*
-function add_collapse() {
- // Add links for show/hide all
- var resulttable = find('table#results-table');
- var showhideall = document.createElement("p");
- showhideall.innerHTML = '<a href="javascript:show_all_extras()">Show all details</a> / ' +
- '<a href="javascript:hide_all_extras()">Hide all details</a>';
- resulttable.parentElement.insertBefore(showhideall, resulttable);
-*/
-function add_collapse() {
- // Add links for show/hide all
- var resulttable = find('table#results-table');
- var showhideall = document.createElement("p");
- showhideall.innerHTML = '<a href="javascript:show_all_extras()">显示详情</a> / ' +
- '<a href="javascript:hide_all_extras()">隐藏详情</a>';
- resulttable.parentElement.insertBefore(showhideall, resulttable);
-
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
3.修改style.css文件主要用来美化测试报告的。
-.expander::after {
- content: " (展开详情)";
- color: #BBB;
- font-style: italic;
- cursor: pointer;
-}
-.collapser::after {
- content: " (隐藏详情)";
- color: #BBB;
- font-style: italic;
- cursor: pointer;
-}
-
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
四.安装汉化版插件
-1.汉化版的pytest-html插件源码上传到GitHub。
https://github.com/13691579846/pytest-html
2.方法一:
-2.1.如果已经安装过pytest-html,先卸载 pip uninstall pytest-html
-2.2.下载插件源码到本地
git clone https://github.com/13691579846/pytest-html
2.3.打开CMD切换到插件中setup.py文件所在目录,执行命令python setup.py install
3.方法二:
-3.1.如果未安装过pytest-html插件,请先执行如下命令安装
pip install pytest-html
3.2.按照方法1的方式下载汉化后的插件,把下载后的插件中的部分附件覆盖到第三方库目录下pytest-html下的部分文件
4.方法三:
-4.1.直接下载汉化后的源码,把源码中的pytest_html直接丢到python第三方库存放目录即可。
-