测试覆盖与矩阵

4. Coverage - 衡量测试的覆盖率

我们已经掌握了如何进行单元测试。接下来,一个很自然的问题浮现出来,我们如何知道单元测试的质量呢?这就提出了测试覆盖率的概念。覆盖率测量通常用于衡量测试的有效性。它可以显示您的代码的哪些部分已被测试过,哪些没有。

coverage.py 是最常用的测量 Python 程序代码覆盖率的工具。它监视您的程序,记录代码的哪些部分已被执行,然后分析源代码以识别已执行和未执行的代码。

我们可以通过下面的方法来安装 coverage.py:

$ pip install coverage

要收集测试覆盖率数据,我们只需要在原来的测试命令前加上 coverage run 即可。比如,如果我们之前是使用pytest arg1 arg2 arg3来进行测试,则现在我们使用:

$ coverage run -m pytest arg1 arg2 arg3

当测试运行完成后,我们可以通过coverage report -m来查看测试覆盖率的报告:

Name                      Stmts   Miss  Cover   Missing
-------------------------------------------------------
my_program.py                20      4    80%   33-35, 39
my_other_module.py           56      6    89%   17-23
-------------------------------------------------------
TOTAL                        76     10    87%

如果希望得到更好的视觉效果,也可以使用 coverage html 命令来生成带注释的 HTML 报告,然后在浏览器中打开 htmlcov/index.html。
75%

不过,更多人选择使用 pytest-cov 插件来进行测试覆盖率的收集。这也是 ppw 的选择。通过 ppw 生成的工程,pytest-cov 已被加入到测试依赖中,因此也就自然安装到环境中去了。

因此,通过 ppw 配置的工程,我们一般不需要直接调用 coverage 命令,而是使用 pytest 命令来进行测试。pytest-cov 插件会自动收集测试覆盖率数据,然后在测试完成后,自动将测试覆盖率报告打印到控制台上。如果希望生成带注释的 HTML 报告,可以使用pytest --cov-report=html命令。对 pytest 我们一般也不需要直接调用,而是通过 tox 来调用。

默认情况下,coverage.py 将测试行(语句)覆盖率,但通过配置,还可以测量分支覆盖率。这需要一些配置。

4.1. 配置 Pycoverage

配置文件的默认名称是。coveragerc,在 ppw 生成的工程中,这个文件处在项目根目录下(读者可以回到第 4 章的结束部分查看 ppw 生成的文件列表)。

如果没有使用其他配置文件,Coverage.py 将从其他常用配置文件中读取设置。如果存在,它将自动从“setup.cfg”或“tox.ini”中读取。如果节 (section) 名称有“coverage:”前缀,则会当成是 coverage 的配置,比如.coveragerc 中有一节名为 run,当它出现在 tox.ini 中,节名字就应该是 [coverage:run]。

我们也可以在 pyproject.toml 中配置 coverage。如果要使用这种方式,需要在 pyproject.toml 中添加一个名为 tool.coverage 的节,然后在这个节中添加配置项。

coverage 的配置项遵循 ini 语法,示例如下:

[run]
branch = True

[report]
# REGEXES FOR LINES TO EXCLUDE FROM CONSIDERATION
exclude_lines =
    # HAVE TO RE-ENABLE THE STANDARD PRAGMA
    pragma: no cover

    # DON'T COMPLAIN ABOUT MISSING DEBUG-ONLY CODE:
    def __repr__
    if self\.debug

    # DON'T COMPLAIN IF TESTS DON'T HIT DEFENSIVE ASSERTION CODE:
    raise AssertionError
    raise NotImplementedError

    # DON'T COMPLAIN IF NON-RUNNABLE CODE ISN'T RUN:
    if 0:
    if __name__ == .__main__.:

    # DON'T COMPLAIN ABOUT ABSTRACT METHODS, THEY AREN'T RUN:
    @(abc\.)?abstractmethod

ignore_errors = True

[html]
directory = coverage_html_report

我们前面提到过可以让 coverage.py 按分支覆盖率来统计,这可以按照第 3 行一样进行配置。[report] 这一节中的配置项可以让 coverage.py 忽略一些不需要统计的代码,比如 debug 代码。[html] 这一节配置了如果生成的 html 文件存放在何处。如果没有指定,将存放在 htmlcov 目录下。

[run] 这一节比较常用的配置项有 include 和 omit,用来特别把某个文件或者目录加入到测试覆盖,或者排除掉。在 [report] 这一节中,也有相同的配置项,两者有所区别。在 [report] 中指定 omit 或者 include,都仅适用于报告的生成,但不影响实际的测试覆盖率统计。

4.2. 发布覆盖率报告

如果我们的项目是开源项目,你可能希望把覆盖率报告发布到网上,这样其他人就可以看到你的项目的覆盖率了。这里我们使用 codecov.io 来发布覆盖率报告。

codecov 是一个在线的代码覆盖率报告服务,它可以从 GitHub、Bitbucket、GitLab 等代码托管平台上获取代码覆盖率报告,然后生成一个在线的报告。这个报告可以让其他人看到你的项目的覆盖率情况。

在 github 中设置 codecov 集成很简单,在浏览器中打开 https://github.com/apps/codecov 页面,点击完成安装,然后在 CI 过程中增加一个上传动作就可以了。在通过 ppw 创建的项目中,我们已经集成了这一步。如果你想在自己的项目中手动执行,则是:

# LINUX
$ curl -Os https://uploader.codecov.io/latest/linux/codecov 
$ chmod +x codecov 
$ ./codecov

# WINDOWS
$ ProgressPreference = 'SilentlyContinue' 
$ Invoke-WebRequest -Uri https://uploader.codecov.io/latest/windows/codecov.exe -Outfile codecov.exe 
$ .\codecov.exe

# MACOS
$ curl -Os https://uploader.codecov.io/latest/macos/codecov
$ chmod +x codecov
$ ./codecov

我们强烈建议仅通过 CI 来上传覆盖率报告,而不是在本地执行。因为本地执行的覆盖率报告,可能会因为本地环境的不同而产生差异。另一方面,在 CI 中执行后,我们还能在 pull request 之后,得到这样的状态报告:

并且还能在 pull request 的注释中看到覆盖率的变化:

这会让你的开源项目看上去非常专业,不是吗?更重要的是,让你的潜在用户更加信任这是一个高质量的项目。

5. TOX 实现矩阵测试

如果我们的软件支持 3 种操作系统,4 个 python 版本,我们就必须在 3 种操作系统上,分别创建 4 个虚拟环境,安装上我们的软件和依赖,再执行测试,上传测试报告。这个动作不仅相当繁琐,还很容易引入错误。

tox 与 CI 结合,就可以帮助我们自动化完成这些环境的创建与测试执行。

5.1. 什么是 Tox?

tox 是一个通用的 Python 虚拟环境管理和测试命令行工具,旨在自动化和标准化 Python 测试。它是简化 Python 软件的打包、测试和发布过程的更大愿景的一部分。大多数项目都使用它来确保软件在多个 Python 解释器版本之间的兼容性。

实际上,tox 主要完成以下工作:

  1. 根据配置创建基于多个版本的 python 虚拟环境,并且保证这些虚拟环境的可复制性(需要与 poetry 或者其它依赖管理工具一起)。
  2. 在多个环境中运行测试和代码检查工具,比如 pytest 和 flake8, black, mypy 等。
  3. 隔离环境变量。tox 不会从系统传递任何环境变量到虚拟环境中,这样可以保证测试的可重复性。

5.2. Tox 的工作原理

下图是 tox 文档显示的工作原理图:

根据这张图,tox 读取配置文件,打包待测试软件,按照配置文件创建虚拟环境,并安装待测试软件和依赖,然后依次执行测试命令。最终,当所有虚拟环境下的测试都通过后,tox 会生成测试报告。

下面,我们主要通过一个典型的配置文件来介绍 tox 是如何配置和工作的。

5.3. 如何配置 Tox

在 ppw 生成的项目中,存在以下 tox.ini 文件:

[tox]
isolated_build = true
envlist = py38, py39, py310, lint
skipsdist = false

[gh-actions]
python =
    3.10: py310
    3.9: py39
    3.8: py38

[testenv:lint]
extras =
    dev
    doc
deps =
    poetry
commands =
    poetry run isort {{ cookiecutter.project_slug }}
    poetry run black {{ cookiecutter.project_slug }} tests
    poetry run flake8 {{ cookiecutter.project_slug }}
    poetry build
    poetry run mkdocs build
    poetry run twine check dist/*

[testenv]
passenv = *
setenv =
    PYTHONPATH = {toxinidir}
    PYTHONWARNINGS = ignore
deps = 
    poetry
extras =
    test
commands =
    poetry run pytest -s --cov={{ cookiecutter.project_slug }} --cov-append --cov-report=xml --cov-report term-missing tests

配置文件仍然是标准的 ini 文件格式(tox 也支持通过 pyproject.toml 来进行配置)。我们主要关注以下几个部分:

5.3.1. [tox] 节

在测试一个 package 之前,tox 首先需要构建一个 sdit 分发包。在打包这件事上,python 走过了很长的一段历程,打包工具和标准也经历了很多变化,这些我们将用专门的一章来介绍。现在我们需要知道的是,最新的标准是 PEP517 和 PEP518,tox 已经支持这两个标准。但是,如果项目本身不支持这两个 PEP,那么 tox 必须回到之前的打包方式。

因此,tox 引入了 isolated_build 这个选项,如果设置为 true,tox 会使用 PEP517 和 PEP518 的方式来打包项目。如果设置为 false,tox 会使用传统的方式 (setup.py) 来打包项目。如果通过 poetry 创建项目,并且在 pyproject.toml 中设置了 requires 和 build-backend 项的话,那么我们是需要设置 isolated_build 为 true 的。

在所有 ppw 创建的项目中,我们都设置了 isolated_build 为 true,这样才与 pyproject.toml 的设置一致。

envlist 选项的含义正如它的名字所示。这里我们指定了 py38, py39, p310 和 lint 这 4 个环境。它们也是虚拟环境的名字,其中 py38, py39, py310 对应的 python 的版本是 3.8, 3.9, 3.10。这里我们还指定了一个 lint 环境,它是用来执行代码检查的。我们没有为它专门指定 python 的版本,因此它会使用当前的 python 版本。

默认地,tox 会在项目根目录下创建.tox 目录,上述虚拟环境就创建在这个目录下:

$ll .tox

total 36
drwxrwxr-x  9 aaron aaron 4096 Jan 20 23:48 ./
drwxrwxr-x 12 aaron aaron 4096 Jan 20 23:48 ../
drwxrwxr-x  5 aaron aaron 4096 Jan 20 23:47 .package/
-rwxrwxr-x  1 aaron aaron    0 Jan 20 23:47 .package.lock*
drwxrwxr-x  3 aaron aaron 4096 Jan 20 23:47 .tmp/
drwxrwxr-x  2 aaron aaron 4096 Jan 20 23:47 dist/
drwxrwxr-x  6 aaron aaron 4096 Jan 20 23:48 lint/
drwxrwxr-x  2 aaron aaron 4096 Jan 20 23:47 log/
drwxrwxr-x  7 aaron aaron 4096 Jan 20 23:47 py38/
drwxrwxr-x  7 aaron aaron 4096 Jan 20 23:48 py39/

列目录时,显示出来存在 lint, py38 和 py39,我们可以进一步查看这些虚拟环境下的 python 版本。但是,我们没有看到 py310,这里因为在我测试时,系统还没有安装 python 3.10 这个版本,因此 tox 会跳过这个版本。

skipsdist 选项用来指示 tox 是否要跳过构建 sdist 分发包的步骤。这个设置主要是为了兼容 python 应用程序,因为 tox 的测试对象除了 library 之外,还可能是服务或者简单的脚本集,这些服务或者脚本集是没有 setup.py 文件,也无法构建 sdist 分发包的。如果没有一个标志让 tox 来跳过构建 sdist 分发包的步骤,那么 tox 会报错:

ERROR: No pyproject.toml or setup.py file found. The expected locations are:
  /Users/christophersamiullah/repos/tox_examples/basic/pyproject.toml or 
  /Users/christophersamiullah/repos/tox_examples/basic/setup.py
You can
  1. Create one:
     https://tox.readthedocs.io/en/latest/example/package.html
  2. Configure tox to avoid running sdist:
     https://tox.readthedocs.io/en/latest/example/general.html
  3. Configure tox to use an isolated_build

这个选项在 tox 中是默认为 false 的,多数情况下无须配置。我们出于帮助大家理解 tox 工作原理的目的介绍它

5.3.2. [testenv]

这一节的配置项适用于所有的虚拟环境。如果在某个虚拟环境下存在特别的选项和动作,需要象 [testenv:lint] 那样定义在自己的节中。

这里我们还额外设置了一些环境变量字段。比如设置了 PYTHONPATH,另外也忽略了一些警告信息。如果我们使用的一些库没有更新,那么将在测试过程中打印大量的 deprecation 警告,从而干扰我们检查测试过程中的错误信息。当然,我们也应该至少在测试中打开一次这种警告,以便知道哪些用法已经需要更新。

一般情况下,tox 是不会把宿主机上的环境变量传递给测试环境的。但有一些情况,比如重要服务的账号和口令,并不适合写在配置文件中,只能配置在宿主机的环境变量中。在这种情况下,我们需要通过 passenv 选项来指定需要传递的环境变量。这个选项的值是一个逗号分隔的字符串,可以是单个的环境变量,也可以象示例中那样,是一个通配符。

!!! Info
在团队开发中,并不是所有的开发者都有权接触到重要服务的账号与口令。如果这些秘密信息配置在代码文件或者相关的配置文件中,就会导致这些秘密暴露给了所有的开发者。此外,如果代码仓库使用的是 gitlab,还可能导致这些信息泄露到互联网上。正确的作法是将这些重要信息仅仅配置在宿主机的环境变量中,这样一来,就只有有权限访问那台机器的人才能接触到这些秘密。

这是一种标准的做法,也得到了 github CI 的支持。在 github CI 中,可以通过在 workflow 文件中使用 env 选项来读取环境变量,再经由 tox 把这些环境变量传递给测试环境。

deps 选项声明了要在虚拟环境中需要安装的 python 库。不同的测试需要的依赖可能各不相同,但在 ppw 生成的项目中,一般我们只需要一个共同的依赖,即 poetry。因为后面的测试命令,我们都会通过 poetry 来调用。

tox 在安装被测试包时,一般是不安装声明为 extra 依赖的。但是,为了运行测试和进行 lint,我们必须安装 pytest, flake8 这些库。在 ppw 生成的工程中,这些依赖被归类为 dev, test 和 doc 这些 extra 依赖。因此,我们也必须在测试中安装。其中 test 依赖是所有的环境都需要的,而 dev 和 doc 则是 lint 时所需要的,因此,我们在 [testenv] 中声明依赖到 test,而只在 [testenv:lint] 中依赖到 dev 和 doc。

接下来就是 commands 字段。这是真正执行测试或者 lint 的地方。这里的命令是:

commands =
    poetry run pytest -s --cov=%package_under_test% --cov-append --cov-report=xml 
    --cov-report term-missing tests

“-s” 是告诉 pytest 不要捕获控制台输入输出。

在 ppw 生成的工程里,我们已经集成了 pytest-coverage 插件,因此,通过适当的配置,我们就可以在测试时同时完成测试覆盖率的统计。–cov 用来指示代码覆盖的范围,这里%package_under_test%需要替换成为我们的库名字。–cov-append 表明此次测试的结果,将追加到之前的统计数据中,而不是完全替换之前的数据。–cov-report 将测试数据输出为 xml 格式。–cov-report 表明应该如何生成报告。

最后,tests 是我们测试代码所在的文件夹。

5.3.3. [testenv.lint]

这一节的语法与 [testenv] 并无二致。只不过要运行的命令不一样。这里就不再一一解释。


本文摘录自《python能做大项目》,将由机械工业出版社出版。原文已发布在大富翁量化上。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/337522.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【SpringBoot技术专题】「开发实战系列」Undertow web容器的入门实战及调优方案精讲

Undertow web容器的入门实战及调优方案精讲 Undertow web容器Undertow 介绍官网API给出一句话概述Undertow:官网API总结特点:Lightweight(轻量级)HTTP Upgrade Support(支持http升级)、HTTP/2 Support支持H…

【Linux 内核源码分析】堆内存管理

堆 堆是一种动态分配内存的数据结构,用于存储和管理动态分配的对象。它是一块连续的内存空间,用于存储程序运行时动态申请的内存。 堆可以被看作是一个由各个内存块组成的堆栈,其中每个内存块都有一个地址指针,指向下一个内存块…

学生公寓智能控电系统的重要性

学生公寓智能控电系统石家庄光大远通电气有限公司学生宿舍内漏电,超负荷用电,违规用电等现象一直是困扰后勤管理的普遍问题。随着学生日常生活方式以及生活用品的改变,电脑以及各种电器逐渐的普及,导致用电量与日俱增,…

竞赛保研 机器视觉人体跌倒检测系统 - opencv python

0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 机器视觉人体跌倒检测系统 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐! 🥇学长这里给一个题目综合评分(每项满分5分) 难度系数&…

翻译: Anaconda 与 miniconda的区别

Anaconda 和 miniconda 是广泛用于数据科学的软件发行版,用于简化包管理和部署。 1. 主要有两个区别: packages包数量: Anaconda 附带了 150 多个数据科学包,而 miniconda 只有少数几个。Interface接口:Anaconda 有…

mfc110.dll丢失是什么意思?全面解析mfc110.dll丢失的解决方法

在使用计算机的过程中,用户可能会遭遇一个常见的困扰,即系统提示无法找到mfc110.dll文件。这个动态链接库文件(DLL)是Microsoft Foundation Classes(MFC)库的重要组成部分,对于许多基于Windows的…

node.js项目express的初始化

目录 1.初始化项目2.配置跨域3.开始编写API3.1准备3.2路由处理函数router_make下的user.js3.3路由模块router下的user.js3.4入口文件app.js里面去新增这段代码3.5启动项目进行测试 👍 点赞,你的认可是我创作的动力! ⭐️ 收藏,你…

设备管理——WinCC 给你神助功

要实现“设备高效”,就必须“管之有道”,来自设备层的数据支撑将是必不可少的,提高设备效能的2个关键在于降低平时停机时间 (MDT) 和提高平均无故障时间 (MTBF)。通常来说,设备维护可大致可分为三个层次:纠正性维护&am…

[Tool] python项目中集成使用Firebase推送功能

背景介绍 目前,App推送功能已经非常普遍,几乎所有App都有推送功能。推送功能可以自己实现,也可以使用第三方提供的推送服务(免费的收费的都有)。本文主要介绍使用Firebase提供的推送服务Firebase Cloud Messaging&…

matlab appdesigner系列-常用13-标签

标签,用来显示各类文本 此示例,就是在标签之外的画布上单击鼠标左键,显示王勃的《滕王阁诗》 操作如下: 1)将2个标签拖拽到画布上,并修改相应文字。将第二个标签的右侧文本信息中的Wordwrap打开&#xf…

[自动化分布式] Zabbix自动发现与自动注册

abbix 自动发现(对于 agent2 是被动模式) zabbix server 主动的去发现所有的客户端,然后将客户端的信息登记在服务端上。 缺点是如果定义的网段中的主机数量多,zabbix server 登记耗时较久,且压力会较大 部署 添加zabb…

六、标准对话框、多应用窗体

一、标准对话框 Qt提供了一些常用的标准对话框,如打开文件对话框、选择颜色对话框、信息提示和确认选择对话框、标准输入对话框等。1、预定义标准对话框 (1)QFileDialog 文件对话框 QString getOpenFileName() 打开一个文件QstringList ge…

uniapp组件库Popup 弹出层 的使用方法

目录 #平台差异说明 #基本使用 #设置弹出层的方向 #设置弹出层的圆角 #控制弹窗的宽度 | 高度 #内容局部滚动 #API #Props #Event 弹出层容器,用于展示弹窗、信息提示等内容,支持上、下、左、右和中部弹出。组件只提供容器,内部内容…

树的一些经典 Oj题 讲解

关于树的遍历 先序遍历 我们知道 树的遍历有 前序遍历 中序遍历 后序遍历 然后我们如果用递归的方式去解决,对我们来说应该是轻而易举的吧!那我们今天要讲用迭代(非递归)实现 树的相关遍历 首先呢 我们得知道 迭代解法 本质上也…

【征服Redis12】redis的主从复制问题

从现在开始,我们来讨论redis集群的问题,在前面我们介绍了RDB和AOF两种同步机制,那你是否考虑过这两个机制有什么用呢?其中的一个重要作用就是为了集群同步设计的。 Redis是一个高性能的键值存储系统,广泛应用于Web应用…

Python实现稳健线性回归模型(rlm算法)项目实战

说明:这是一个机器学习实战项目(附带数据代码文档视频讲解),如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 稳健回归可以用在任何使用最小二乘回归的情况下。在拟合最小二乘回归时,我们可能会发现一些…

人才测评,招聘工程技术经理胜任素质模型与任职资格

招聘工程技术经理是企业中的重要职位之一,为了确保招聘到胜任的人才,需要制定一个胜任力素质模型和任职资格。 1.专业知识技能:工程技术经理需要拥有深厚的专业技术知识,能够熟练掌握工程设计、生产制造、质量管理、安全管理等方面…

macOS 设置屏幕常亮 不休眠

Apple M1 Pro macOS Sonoma设置“永不”防止进入休眠 macOS Sonoma 设置“永不” 防止进入休眠

开源进程/任务管理服务Meproc使用之HTTP API

本文讲述如何使用开源进程/任务管理服务Meproc的HTTP API管理整个服务。 Meproc所提供的全部 API 的 URL 都是相同的。 http://ip:port/proc例如 http://127.0.0.1:8606/proc在下面的小节中,我们使用curl命令向您展示 API 的方法、参数和请求正文。 启动任务 …

Tensorflow 入门基础——向LLM靠近一小步

进入tensflow的系统学习,向LLM靠拢。 目录 1. tensflow的数据类型1.1 数值类型1.2 字符串类型1.3 布尔类型的数据 2. 数值精度3. 类型转换3.1 待优化的张量 4 创建张量4.1 从数组、列表对象创建4.2 创建全0或者1张量4.3 创建自定义数值张量 5. 创建已知分布的张量&…