admin 管理员组

文章数量: 888398

pytest与coverage联合使用

目录

安装 

运行方式

命令行方式

 .py文件方式

测试结果各参数含义

pytest与coverage联合使用示例

运行方式

方式一:coverage的终端使用

方式二:运行run.py

report HTML页面结果


覆盖率测量通常用于衡量测试的有效性。Coverage可以显示测试正在执行代码的哪些部分,以及哪些部分没有被执行。

coverage作用:用于检查代码测试覆盖率的工具。

官方文档:Coverage.py — Coverage.py 6.6.0b1 documentation

 

安装 

# 安装
$ pip install coverage# 验证安装版本
$ coverage --version
Coverage.py, version 6.5.0 with C extension
Full documentation is at 

运行方式

命令行方式

# 搜集被测代码覆盖率信息,保存到 .coverage 文件中
$ coverage run 测试文件.py# 生成覆盖率统计结果报告
$ coverage report# 以HTML的形式生成覆盖率统计结果报告
$ coverage html

 .py文件方式

命名为run.py文件,放置在项目根目录下,具体如下:

import coverage
import pytest# 实例化对象
cov = coverage.coverage()
cov.start()# 测试
pytest.main(["-v", "-s"])# 结束分析
cov.stop()# 结果保存
cov.save()# 命令行模式展示结果,并展示未执行代码具体行数,用于测试结果查看使用
cov.report(show_missing=True)# 生成HTML覆盖率结果报告
cov.html_report(directory="res_html")

运行方式:进入到run.py文件所在路径执行以下命令

# 运行.py文件
$ python run.py

测试结果各参数含义

终端report里测试结果各参数含义:

  • Stmts :代码总行数
  • Miss:未执行代码行数
  • Cover:代码覆盖率

report HTML中测试结果各参数含义:

  • statements :代码总行数,不包含空行和注释行
  • missing:未执行代码行数
  • coverage:代码覆盖率

pytest与coverage联合使用示例

目录结构如下:

运行测试后的文件夹目录结构:

 运行测试+生成report HTML后的文件夹目录结构:

 各py文件内容具体如下:

# demofunc.pydef add(a, b):if isinstance(a, int) and isinstance(b, int):return a+belse:raise TypeError("数据类型错误")
# demofunc2.pydef add(a, b):raise NameError("名称错误")if isinstance(a, int) and isinstance(b, int):return a+belse:raise TypeError("数据类型错误")
# test_func.pyimport pytest
from demofunc import addclass Testfunc:# 正常测试用例def test_add_by_class(self):assert add(2, 3) == 5# 异常测试用例,期望结果为抛出TypeError异常def test_add_by_func_aaa(self, *args, **kwargs):with pytest.raises(TypeError) as E:add("3", 4)print(E.type)print(E.value)print(E.traceback)def test_zero_division_long():with pytest.raises(ZeroDivisionError) as excinfo:1 / 0print("----------------")print(excinfo.type)print(excinfo.value)print(excinfo.traceback)
# test_func2.pyimport pytest
from demofunc2 import addclass Testfunc:# 异常用例def test_add_by_func_aaa(self, *args, **kwargs):# 将预期中多个错误信息组成一个元组# with pytest.raises((TypeError, NameError), match=r"错误") as E:with pytest.raises((TypeError, NameError), match=r".*错.*$") as E:add("3", 4)# 检查断言装饰器@pytest.mark.xfail(raises=(TypeError, NameError))def test_add_by_func_aaa2(self):add("3", 4)

运行方式

方式一:coverage的终端使用

使用pytest作为run.py文件的内容:

# run.pyimport pytestif __name__ == "__main__":pytest.main(["-v", "-s"])

注意:使用此方式运行后,run.py文件会计入测试覆盖率中

运行后终端显示的结果如下:

# 进入到已安装了coverage的环境中# 运行run.py进行测试
PS F:\workspace\练习题\assertcode> coverage run run.py
======================================================== test session starts ========================================================
platform win32 -- Python 3.7.3, pytest-7.1.3, pluggy-1.0.0 -- c:\users\xxx\appdata\local\programs\python\python37\python.exe    
cachedir: .pytest_cache
rootdir: F:\workspace\练习题\assertcode
plugins: cov-4.0.0
collected 5 items                                                                                                                     test_case/test_func.py::Testfunc::test_add_by_func_aaa <class 'TypeError'>
数据类型错误
[<TracebackEntry F:\workspace\练习题\assertcode\test_case\test_func.py:15>, <TracebackEntry F:\workspace\练习题\assertcode\demofunc.py:5>]
PASSED
test_case/test_func.py::test_zero_division_long ----------------
<class 'ZeroDivisionError'>
division by zero
[<TracebackEntry F:\workspace\练习题\assertcode\test_case\test_func.py:23>]
test_case/test_func2.py::Testfunc::test_add_by_func_aaa PASSED
test_case/test_func2.py::Testfunc::test_add_by_func_aaa2 XFAIL=================================================== 4 passed, 1 xfailed in 0.05s ================================================================================== # 查看测试覆盖报告
PS F:\workspace\练习题\assertcode> coverage report
Name                      Stmts   Miss  Cover
---------------------------------------------
demofunc2.py                  5      3    40%
demofunc.py                   4      0   100%
run.py                        3      0   100%
test_case\test_func2.py       8      0   100%
test_case\test_func.py       18      0   100%
---------------------------------------------
TOTAL                        38      3    92%

方式二:运行run.py

使用pytest+coverage结合作为run.py文件的内容:

# run.pyimport coverage
import pytestcov = coverage.coverage()cov.start()pytest.main(["-v", "-s"])cov.stop()
cov.save()cov.report()
cov.html_report(directory="res_html")

注意:使用此方式运行后,run.py文件不计入测试覆盖率中

运行后终端显示的结果如下:

PS F:\workspace\练习题\assertcode> & C:/Users/xxx/Envs/ctpenv/Scripts/python.exe f:/workspace/练
习题/assertcode/run.py
======================================== test session starts =========================================
platform win32 -- Python 3.7.3, pytest-7.1.3, pluggy-1.0.0 -- C:\Users\xxx\Envs\ctpenv\Scripts\python.exe
cachedir: .pytest_cache
rootdir: F:\workspace\练习题\assertcode
plugins: anyio-3.6.1
collected 5 itemstest_case/test_func.py::Testfunc::test_add_by_func_aaa <class 'TypeError'>
数据类型错误
[<TracebackEntry F:\workspace\练习题\assertcode\test_case\test_func.py:15>, <TracebackEntry F:\workspace\练习题\assertcode\demofunc.py:5>]
PASSED
test_case/test_func.py::test_zero_division_long ----------------
<class 'ZeroDivisionError'>
division by zero
[<TracebackEntry F:\workspace\练习题\assertcode\test_case\test_func.py:23>]
test_case/test_func2.py::Testfunc::test_add_by_func_aaa PASSED
test_case/test_func2.py::Testfunc::test_add_by_func_aaa2 XFAIL=================================================== 4 passed, 1 xfailed in 0.05s ================================================================================== 
Name                      Stmts   Miss  Cover
---------------------------------------------
demofunc2.py                  5      3    40%
demofunc.py                   4      0   100%
test_case\test_func2.py       8      0   100%
test_case\test_func.py       17      0   100%
---------------------------------------------
TOTAL                        34      3    91%

report HTML页面结果

总计结果页面显示:

单个文件覆盖详情显示:

本文标签: pytest与coverage联合使用