测试覆盖与矩阵

news2024/11/26 3:47:20

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能做大项目》,将由机械工业出版社出版。原文已发布在大富翁量化上。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【linux驱动】用户空间程序与内核模块交互-- IOCTL和Netlink

创建自定义的IOCTL(输入/输出控制)或Netlink命令以便用户空间程序与内核模块交互涉及几个步骤。这里将分别介绍这两种方法。 一、IOCTL 方法 1. 定义IOCTL命令 在内核模块中,需要使用宏定义你的IOCTL命令。通常情况下,IOCTL命令…

【js】js 异步机制详解 Generator / Async / Promise

三种语法功能放在一起,是因为他们都有相似特点: 维护某种状态在未来恢复状态并执行 本文重点回答以下几个问题: 为什么 Generator 和 Async 函数的 代码执行流 都可以简化成树形结构?async 函数为什么返回一个 promise&#xf…

关于常见分布式组件高可用设计原理的理解和思考

文章目录 1. 数据存储场景和存储策略1.1 镜像模式-小规模数据1.2 分片模式-大规模数据 2. 数据一致性和高可用问题2.1 镜像模式如何保证数据一致性2.2 镜像模式如何保证数据高可用2.2.1 HA模式2.2.2 分布式选主模式 2.3 分片模式如何数据一致性和高可用 3. 大规模数据集群的架构…

Qt事件过滤

1.相关说明 监控鼠标进入组件、出组件、点击组件、双击组件的事件,需要重写eventFilter函数 2.相关界面 3.相关代码 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui-&…

【MySQL】一文总结MVCC多版本并发控制

目录 MVCC 介绍当前读和快照读当前读快照读 MVCC 原理解析隐式字段Undo Log版本链Read ViewRead View 可见性原则 RC 和 RR 下的 Read ViewRC 下的 Read ViewRR 下的 Read View小结RR 级别下能否防止幻读总结 MVCC 介绍 在当今高度并发的数据库环境中,有效的并发控…

【Python学习】Python学习21- 正则表达式(1)

目录 【Python学习】Python学习21- 正则表达式(1) 前言re.match函数实例 re.search方法re.match与re.search的区别参考 文章所属专区 Python学习 前言 本章节主要说明Python的正则表达式。 正则表达式是一个特殊的字符序列,它能帮助你方便的…

鸿蒙 HarmonyOS ArkTS ArkUI 动画 中心缩放、顶部缩放、纵向缩放

EntryComponentstruct Index {State widthA: number 200State heightA: number 200onPageShow():void{animateTo ( {duration: 2000,iterations: -1,curve:Curve.Linear}, () > {this.widthA 0this.heightA 0} )}build() {Column() {// 中心缩放Column(){}.width(this.wi…

Golang 搭建 WebSocket 应用(八) - 完整代码

本文应该是本系列文章最后一篇了,前面留下的一些坑可能后面会再补充一下,但不在本系列文章中了。 整体架构 再来回顾一下我们的整体架构: 在我们的 demo 中,包含了以下几种角色: 客户端:一般是浏览器&am…

MyBatis 系列:MyBatis 源码环境搭建

文章目录 一、环境准备二、下载 MyBatis 源码和 MyBatis-Parent 源码三、创建空项目、导入项目四、编译 mybatis-parent五、编译 mybatis六、测试总结 一、环境准备 jdk:17 maven:3.9.5 二、下载 MyBatis 源码和 MyBatis-Parent 源码 Mybatis&#x…

【Linux】进程间通信——system V 共享内存、消息队列、信号量

需要云服务器等云产品来学习Linux的同学可以移步/–>腾讯云<–/官网&#xff0c;轻量型云服务器低至112元/年&#xff0c;优惠多多。&#xff08;联系我有折扣哦&#xff09; 文章目录 写在前面1. 共享内存1.1 共享内存的概念1.2 共享内存的原理1.3 共享内存的使用1.3.1 …

在Java中调企微机器人发送消息到群里

目录 如何使用群机器人 消息类型及数据格式 文本类型 markdown类型 图片类型 图文类型 文件类型 模版卡片类型 文本通知模版卡片 图文展示模版卡片 消息发送频率限制 文件上传接口 Java 执行语句 String url "webhook的Url"; String result HttpReque…

二叉树的直径(LeetCode 543)

文章目录 1.问题描述2.难度等级3.热门指数4.解题思路参考文献 1.问题描述 给你一棵二叉树的根节点&#xff0c;返回该树的直径 。 二叉树的 直径 是指树中任意两个节点之间最长路径的长度 。这条路径可能经过也可能不经过根节点 root 。 两节点之间路径的长度由它们之间边数…

Odrive 学习系列四:如何使用脚本自动初始化odrive配置

一、背景: 在学习markbase的教程后,发现odrive的初始化配置命令确实有点多。尽管odrive有自动补全: 且可以通过 ctrl + → 来快速补全: 但是对初学者而言,仍旧有比较大的工作量。 而针对于此,我们可以通过powershell脚本的方式来解决这个问题。 二、设计初始化…

继电器开关电路图大全

继电器是一种电控制器件&#xff0c;是当输入量&#xff08;激励量&#xff09;的变化达到规定要求时&#xff0c;在电气输出电路中使被控量发生预定的阶跃变化的一种电器。它具有控制系统&#xff08;又称输入回路&#xff09;和被控制系统&#xff08;又称输出回路&#xff0…

Siemens-NXUG二次开发-导入与导出(可移除参数)prt文件[Python UF][20240121]

Siemens-NXUG二次开发-导入与导出&#xff08;可移除参数&#xff09;prt文件[Python UF][20240121] 1.python uf函数1.1 NXOpen.UF.Part.Import1.2 NXOpen.UF.Part.ImportPartModes1.3 NXOpen.UF.Group.AskGroupData1.4 NXOpen.UF.Obj.AskTypeAndSubtype1.5 NXOpen.UF.Part.Ex…

Frenet坐标系下动态街道场景的最优轨迹生成

0 前言 有两个主要算法已经在实际中使用&#xff1a; &#xff08;1&#xff09;大多数研究组采用插值来解决规划问题&#xff0c;如奥迪、斯坦福最近演示中使用了回旋曲线&#xff0c;贝塞尔以及多项式曲线也被其他研究组使用。主要原因是在结构化环境中增强映射可以提供所需…

第十一站:多态练习ODU

实现动态切换 ODU.h #pragma once #include <iostream> using namespace std; #define ODU_TYPE_311_FLAG "311" #define ODU_TYPE_335_FLAG "335" enum class ODU_TYPE {ODU_TYPE_311,ODU_TYPE_335,ODU_TYPE_UNKNOW };class ODU{ public:ODU();//发…

Jan AI本地运行揭秘:首次体验,尝鲜科技前沿

&#x1f31f;&#x1f30c; 欢迎来到知识与创意的殿堂 — 远见阁小民的世界&#xff01;&#x1f680; &#x1f31f;&#x1f9ed; 在这里&#xff0c;我们一起探索技术的奥秘&#xff0c;一起在知识的海洋中遨游。 &#x1f31f;&#x1f9ed; 在这里&#xff0c;每个错误都…

带POE网络变压器与2.5G/5G/10G网络变压器产品特点介绍

Hqst华轩盛(石门盈盛)电子导读&#xff1a;一起来了解带POE网络变压器与2.5G/5G/10G网络变压器产品特点&#xff1f; 一﹑带POE网络变压器与2.5G/5G/10G网络变压器产品特点介绍 首先、POE网络变压器产品与常规不带POE产品的区别&#xff1a; 带POE网络变压器主要要求是耐电流等…

按键检测知识

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 例如&#xff1a;…