Open hanxi opened 1 year ago
目的是使用 pytest 实现一套静态检查工具,采用 pytest 是因为一套完整的静态检查工具的产出的检查报告跟 pytest-html 产出的检查报告非常像,而且检查工具的每个步骤就相当于一个测试用例,并且测试用例直接可以有前后依赖关系。正式利用了 pytest 提供的这一套基础设施,可以比较方便的造出这个静态检查工具。
工程目录结构如下:
. ├── gen_report.sh ├── install.sh ├── pytest-html │ ├── codecov.yml │ ├── docs │ ├── Gruntfile.js │ ├── LICENSE │ ├── package.json │ ├── Pipfile │ ├── pyproject.toml │ ├── README.rst │ ├── setup.cfg │ ├── setup.py │ ├── src │ ├── testing │ └── tox.ini ├── reports │ └── report.html └── src ├── contest.py ├── init_test.py └── __pycache__
gen_report.sh 用于生成测试报告
now=$(date +"%Y-%m-%d-%H-%M-%S") #pytest --html=reports/report-$now.html --self-contained-html src pytest --html=reports/report.html --self-contained-html src
正式环境运行时,给生成的报告文件加上时间。为了方便测试,测试环境就不加时间了。
install.sh 用于安装 pytest-html 包,由于需要修改,所以直接把包引入工程目录了。
cd pytest-html pip install -e .
reports 目录用于存放生成的报告文件, src 目录用于存放测试用例。
接下来会根据制作静态检查工具所需的环境,对 pytest 以及 pytest-html 进行配置以及改造。
修改 src/contest.py 文件,使用 pytest_addoption 接口来新增参数:
pytest_addoption
import pytest def pytest_addoption(parser): parser.addoption( "--branch", action="store", default="master", help="branch: 分支名" ) @pytest.fixture() def branch(request): return request.config.getoption("--branch")
并使用 pytest.fixture 装饰器新增一个 branch 参数给测试用例使用。
pytest.fixture
branch
想要某些测试用例依赖某些测试用例成功执行,可以使用 pytest.mark.skipif 实现,在满足第一个参数为 True 时跳过用例。
pytest.mark.skipif
True
新键文件 src/init_test.py ,pytest 是会自动执行以 test 开始或者结尾的 py 文件的。
src/init_test.py
首先定义一个全局变量 g_init_succ 用来标记是否初始化完毕,然后用这个全局变量创建一个装饰器 checkinit = pytest.mark.skipif(not g_init_succ, reason='初始化失败') 。
g_init_succ
checkinit = pytest.mark.skipif(not g_init_succ, reason='初始化失败')
接下来在第 1 个测试用例中,如果 init() 执行成功,则将 g_init_succ 设置为 True ,在第 2 个测试用例就可以使用前面创建的装饰器 checkinit 了。达到的效果就是 init() 执行成功,才执行第 2 个测试用例 test_need_init ,如果 init() 执行失败就不执行第 2 个测试用例了。
init()
checkinit
test_need_init
import pytest g_init_succ = False checkinit = pytest.mark.skipif(not g_init_succ, reason='初始化失败') # 初始化环境 def init(): #return True return False def test_init(branch): global g_init_succ print("in test_init") # branch 就是前面 fixture 装饰器创建的参数 print("branch:", branch) if init(): g_init_succ = True else: assert False, "初始化环境失败" print("init_succ", g_init_succ) @checkinit def test_need_init(): print("g_init_succ:", g_init_succ) print("succ") pass
可以弄个 env 表,修改 conftest.py 文件:
conftest.py
@pytest.fixture() def env(request): return { 'branch': request.config.getoption("--branch"), 'svn_root': "http://test.com", 'svn_user': "user", 'svn_passwd': "passwd", }
修改 conftest.py 文件:
def pytest_configure(config): config._metadata.clear() config._metadata['分支'] = config.getoption('--branch')
def pytest_html_results_table_header(cells): cells.pop(-1) # 删除link列 def pytest_html_results_table_row(report, cells): cells.pop(-1) # 删除link列
def pytest_html_report_title(report): report.title = "版本静态检查报告"
参考这篇文章: https://www.cnblogs.com/linuxchao/p/linuxchao-pytest-html.html 翻译成果: https://github.com/hanxi/pytest-html-cn 效果预览:
跟前面删除 link 列一样,使用 pytest_html_results_table_header 和 pytest_html_results_table_row 接口实现。 并通过 pytest_runtest_makereport 接口新增列所需的数据。
pytest_html_results_table_header
pytest_html_results_table_row
pytest_runtest_makereport
from py.xml import html def pytest_html_results_table_header(cells): cells.pop(1) # 删除检查列 cells.pop(-1) # 删除link列 cells.insert(1, html.th("描述")) def pytest_html_results_table_row(report, cells): cells.pop(1) # 删除检查列 cells.pop(-1) # 删除link列 cells.insert(1, html.td(report.description)) @pytest.hookimpl(hookwrapper=True) def pytest_runtest_makereport(item, call): outcome = yield report = outcome.get_result() report.description = str(item.function.__doc__)
自动折叠通过和跳过,之前翻译漏了这部分导致自动折叠会有问题的。
https://github.com/hanxi/pytest-html-cn/commit/5055c5b7b5f312894a98ff3dd2e2efe154b59b72
比如错误,预期失败,预期通过我暂时用不上,就屏蔽了。
https://github.com/hanxi/pytest-html-cn/commit/4c85de932c673eaa96304e863e0b0597a330dc8a
使用 pytest_html_results_table_html 接口修改详情,先清空 data ,然后重新构造 data 。
pytest_html_results_table_html
比如 skipped 的情况下,默认打印格式是这样的:
('/home/hanxi/work/pytest-demo/src/init_test.py', 21, 'Skipped: 初始化失败')
我只想打印跳过的原因,就删除首位括号,然后切割字符串,只打印最后一个元素。
想要隐藏 failed 的时候输出的报错堆栈,就不输出堆栈数据。
从 report.sections 获取 stdout 数据,然后又不输出标题。
这些都是从 def _populate_html_log_div 函数的实现里修改过来的:
def _populate_html_log_div
def pytest_html_results_table_html(report, data): del data[:] log = html.div(class_="log") if report.skipped and report.longrepr: arr = report.longreprtext.strip("()").split(",") skip_msg = arr[len(arr)-1] log.append(html.span(raw(escape(skip_msg)))) elif report.failed and report.longrepr: pass elif report.longrepr: text = report.longreprtext or report.full_text for line in text.splitlines(): separator = line.startswith("_ " * 10) if separator: log.append(line[:80]) else: exception = line.startswith("E ") if exception: log.append(html.span(raw(escape(line)), class_="error")) else: log.append(raw(escape(line))) log.append(html.br()) for section in report.sections: header, content = map(escape, section) converter = Ansi2HTMLConverter( inline=False, escaped=False, ) content = converter.convert(content, full=False) log.append(raw(content)) log.append(html.br()) data.append(log)
工具地址: https://github.com/hanxi/version-check-tool
工程目录结构如下:
gen_report.sh 用于生成测试报告
正式环境运行时,给生成的报告文件加上时间。为了方便测试,测试环境就不加时间了。
install.sh 用于安装 pytest-html 包,由于需要修改,所以直接把包引入工程目录了。
reports 目录用于存放生成的报告文件, src 目录用于存放测试用例。
接下来会根据制作静态检查工具所需的环境,对 pytest 以及 pytest-html 进行配置以及改造。
获取命令行参数
修改 src/contest.py 文件,使用
pytest_addoption
接口来新增参数:并使用
pytest.fixture
装饰器新增一个branch
参数给测试用例使用。配置测试用例之间的依赖关系
想要某些测试用例依赖某些测试用例成功执行,可以使用
pytest.mark.skipif
实现,在满足第一个参数为True
时跳过用例。新键文件
src/init_test.py
,pytest 是会自动执行以 test 开始或者结尾的 py 文件的。首先定义一个全局变量
g_init_succ
用来标记是否初始化完毕,然后用这个全局变量创建一个装饰器checkinit = pytest.mark.skipif(not g_init_succ, reason='初始化失败')
。接下来在第 1 个测试用例中,如果
init()
执行成功,则将g_init_succ
设置为True
,在第 2 个测试用例就可以使用前面创建的装饰器checkinit
了。达到的效果就是init()
执行成功,才执行第 2 个测试用例test_need_init
,如果init()
执行失败就不执行第 2 个测试用例了。变量比较多的情况怎么办?
可以弄个 env 表,修改
conftest.py
文件:修改 Environment 里显示的内容
修改
conftest.py
文件:删除 link 列
修改
conftest.py
文件:修改标题
翻译成中文
参考这篇文章: https://www.cnblogs.com/linuxchao/p/linuxchao-pytest-html.html 翻译成果: https://github.com/hanxi/pytest-html-cn 效果预览:
删除检查列和link列,新增描述列
跟前面删除 link 列一样,使用
pytest_html_results_table_header
和pytest_html_results_table_row
接口实现。 并通过pytest_runtest_makereport
接口新增列所需的数据。自动折叠
自动折叠通过和跳过,之前翻译漏了这部分导致自动折叠会有问题的。
https://github.com/hanxi/pytest-html-cn/commit/5055c5b7b5f312894a98ff3dd2e2efe154b59b72
隐藏不想要的复选框
比如错误,预期失败,预期通过我暂时用不上,就屏蔽了。
https://github.com/hanxi/pytest-html-cn/commit/4c85de932c673eaa96304e863e0b0597a330dc8a
修改详情
使用
pytest_html_results_table_html
接口修改详情,先清空 data ,然后重新构造 data 。比如 skipped 的情况下,默认打印格式是这样的:
我只想打印跳过的原因,就删除首位括号,然后切割字符串,只打印最后一个元素。
想要隐藏 failed 的时候输出的报错堆栈,就不输出堆栈数据。
从 report.sections 获取 stdout 数据,然后又不输出标题。
这些都是从
def _populate_html_log_div
函数的实现里修改过来的:最后
工具地址: https://github.com/hanxi/version-check-tool