部分测试:只运行与您的更改相关的测试
项目描述
部分测试
持续集成实践使得代码频繁且经过验证(构建和测试)地贡献到共享仓库成为可能。但是,随着项目的增长,它们的测试套件也增长,运行它们所需的时间也随之增加。小而有限制的更改不需要运行所有测试,其中大多数可能都不相关。为了提高开发者的生产力和减少资源使用,我们已实现了部分测试。通过记录之前运行中的覆盖率数据,它确定了针对每个新的更改或拉取请求应运行哪些测试。
为了保持覆盖率数据最新,并确保所有测试偶尔仍然运行,主分支构建同时执行整个测试套件并记录覆盖率。主分支的覆盖率数据以.coverage
文件的形式保存(该文件是coveragepy>=5.0的sqlite数据库文件,详细信息请参阅此处),而非主分支使用该文件来运行分支中包含的更改的相关测试。
为了简化,我们将文件视为最小的可能更改单元(而不是在行级别进行)。也就是说,如果某行已更改,它被视为整个文件已更改。这种方法简化了部分测试的复杂性,并为过滤掉实际相关的测试提供了更广泛的保护网。
如上图所示,一旦文件被修改,就会根据文件类型出现几种不同的测试场景。也可能需要组合使用。不同的文件类型如下
- 部分测试仅适用于在git中的项目。
源代码文件
包括任何包含代码但不属于测试套件的文件。它们通常具有Python扩展名.py
,但也可能是.cpp
、.c
等。
当修改时
a) 检查保存的覆盖率数据以找到所有相关的测试(测试名称)。
b) 对于每个测试名称,找到具有其定义的文件。
c) 将步骤b中的文件传递给pytest
(或任何其他测试工具)。
当添加新文件时,必须运行完整的测试套件。
测试代码文件
包括任何包含代码并默认属于测试套件的文件,默认情况下包括tests/
下的所有Python文件。它们具有Python扩展名.py
。当修改时,运行更改文件中包含的所有测试。
当添加新的测试文件时,必须运行该文件中的所有测试。当删除一个时,不需要运行其中的任何测试。
此外,测试目录下的一些文件可能是被其他测试文件导入的实用文件。因此,对于修改后的测试文件,我们需要以下两个步骤
a) 检查哪些测试使用该文件(就像非测试代码文件一样)
b) 运行修改文件中的测试
特殊/配置文件
包括任何不包含代码但影响代码运行方式的文件。例如:setup.cfg
当修改或添加新文件时,必须运行所有测试。
每个项目都应该能够指定哪些文件和/或文件扩展名应被视为特殊文件,请参阅下面的详细说明。
我们将conftest.py
(pytest)包括在这个文件类别中,尽管它最初看起来像代码文件(.py)或测试文件(位于测试目录下)。
非代码文件
包括任何不包含代码的文件。例如,README或.md
文件。
当修改或添加新文件时,不需要运行测试。
总结如下
源代码文件 | 测试文件 | 非代码文件 | 特殊/配置文件 | |
---|---|---|---|---|
扩展名 | .py, .cpp, .c | .py | .md | .cfg |
修改 | 运行使用该文件的测试 | 运行测试 a) 在修改的文件中 b) 使用该文件 | 不运行测试 | 运行所有测试 |
添加新文件 | 运行所有测试 | 在新的文件中运行测试 | 不运行测试 | 运行所有测试 |
已删除 | 运行使用该文件的测试 | 不要运行该文件 | 不运行测试 | 运行所有测试 |
用法
安装
pip install partialtesting # soon to be published in pypi
安装完成后,二进制文件 partialtest
和 partialtesting
(它们是相同的,后者保留以兼容)将在您的虚拟环境中可用
$ partialtesting --help
Usage: partialtesting [OPTIONS]
Partial Testing (PT) identifies which tests need to be run for a given
change set, improving the speed of testing, developer productivity and
resource usage. To achieve this, PT relies on enriched coverage data
generated before hand, generally by a master-branch build running on a CI
(e.g. Jenkins).
PT expects to find the coverage data in a directory with the below
pattern: <coverage_dir>/<project_name>. Use the options for this script to
specify them
More information available in the README.
Options:
--coverage-dir TEXT Path to the saved coverage data. Set a default
path by setting the below in ~/.partialtesting:
[coverage] dir=<path>
--project-name TEXT Project name (e.g. numpy).The name will be used
to get the path to the coverage data for this
project:
<coverage_dir>/<project_name>/.../.coverage
[required]
本地使用 Partialtesting
本节展示了如何在本地上使用 partialtesting
,但与其结合持续集成系统(CI)如 Jenkins 使用时,其便利性和优势最大化。下面将进行解释。
要本地使用 partialtesting
,请指定存储覆盖数据的目录。也就是说,在先前的整个测试套件运行期间生成的覆盖数据或从主构建中生成的覆盖数据,更多详情请参阅上面的 CI 部分。
例如,假设您的项目代码库(git)如下
$ tree
├── code1.py
├── code2.py
├── .coveragerc # explained below
└── tests
├── __init__.py
└── test_code1.py
并且文件具有以下内容
$ cat code1.py
def myfunc1():
print('in myfunc1')
def myfunc2():
print('in myfunc2')
myfunc3()
def myfunc3():
print('in myfunc3')
$ cat code2.py
def myfunc4():
print('in myfunc4')
$ cat tests/test_code1.py
import code1
def test_code1():
code1.myfunc1()
def test_code2():
code1.myfunc2()
现在,运行整个测试套件以生成 partialtesting
将使用的覆盖数据。
$ pip install coverage>=5 pytest
$ PYTHONPATH='.' coverage --branch run -m pytest tests/
================================================================================== test session starts ===================================================================================
platform darwin -- Python 3.8.1, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /Users/fersarr/workspace/fake_project
collected 2 items
tests/test_code1.py .. [100%]
=================================================================================== 2 passed in 0.01s ====================================================================================
确保您有 coverage>=5.0
和一个 .coveragerc
文件,该文件告诉 coverage 记录测试上下文(更多信息)
$ cat .coveragerc
[run]
dynamic_context = test_function
coverage ... pytest
命令应该已生成一个 .coverage
文件,它是一个 SQLite 数据库
$ sqlite3 .coverage ".tables"
arc coverage_schema line_bits tracer
context file meta
现在,将 .coverage
文件移动到将存储此项目覆盖数据的目录中
$ mkdir -p saved_coverage/fake_project/ && cp .coverage saved_coverage/fake_project/
$ tree
├── saved_coverage
│ └── fake_project
│ └── .coverage
好了,一切准备就绪,可以开始使用 partialtesting
,让我们修改一个文件并运行 PT
。
通过添加一行修改了代码文件
$ git diff
diff --git a/code1.py b/code1.py
index faecfed..40f81cc 100644
--- a/code1.py
+++ b/code1.py
@@ -1,5 +1,6 @@
def myfunc1():
print('in myfunc1')
+ print('changing myfunc1')
运行 partialtesting
$ partialtest --coverage-dir saved_coverage --project-name fake_project --compare-to-branch master
...
INFO:root:Partial Testing: using coverage file 'saved_coverage/fake_project/.coverage'
...
INFO:root:Creating file test_files_to_run.txt
INFO:root:Partial Testing: relevant test files:
tests/test_code1.py
正如 PT
告诉我们的,对于我们所做的更改,我们需要在 tests/test_code1.py
中运行测试。
CI(例如 Jenkins)上的 Partialtesting
如上所述,partialtesting 可以在持续集成系统(CI)中(如 Jenkins)使用,以提高资源使用率并减少构建时间。过程与上述本地运行类似,但区别在于设置主分支以生成覆盖数据 .coverage
并将其保存在可访问的目录中,以便非主分支可以运行 partialtesting
并使用它。
- 在主分支上使用覆盖运行整个测试套件并将
.coverage
文件保存到路径
$ coverage run -p --branch pytest tests/
$ cp .coverage jenkins/saved_coverage/project_x/907/ # build number 907
提示:添加/创建一个 .coveragerc
文件,如上所述,以保存与覆盖数据一起的测试上下文。
- 在非主分支上使用
partialtesting
以获取给定分支更改应运行的测试列表。
partialtesting --project-name project_x --coverage-dir /jenkins/saved_coverage/ --git-diff-use-head --special-files "'setup.py', 'setup.cfg'" --special-extensions "'.pkl', '.h5', '.csv'"
需要运行的测试列表输出到文件 test_files_to_run.txt
(可通过 --output-file
自定义)
将这些测试提供给 pytest
或您首选的测试工具。
致谢
自 2019 年以来,Partial Testing 在 Man Alpha Tech 上积极开发。
原始概念和实现: Fernando Saravia Rajal
贡献者
相关链接
项目详情
下载文件
下载适用于您的平台的文件。如果您不确定选择哪个,请了解更多关于 安装软件包 的信息。
源代码分发
构建的分发版
partialtesting-1.0.tar.gz的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 06133d723d707c2d9c71de08dd58ac7a5ec582c84fa0675e41e023ba5a29f813 |
|
MD5 | eaf6d65d08b72028cbc72bfd370fe6cf |
|
BLAKE2b-256 | fe246544b66b96e93baf3244e7cbe0f54d39ed391a9fdc3ad66cee0120f9a87e |
partialtesting-1.0-py3.8.egg的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 1ab8a0ef8ad8d3cdce3cd61b99c9899b1de1e3ca10081a9be0970d132b73e35d |
|
MD5 | d42379f5e38dcd9c32ea438180094274 |
|
BLAKE2b-256 | 1882d6f93bd4468a8e8de2e806ce474edf9cdea7a49b2021127488339b3adb9b |
partialtesting-1.0-py2.py3-none-any.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 161bbe2edcda0bbe39fbca739de34b97fdbd3b451d1ff77ed0eb6d3cc05a4665 |
|
MD5 | 9f4719e2aaddc5e4c0e7f66de5efe821 |
|
BLAKE2b-256 | a491eb13bfd3cce2f06478999775f55ee6f1ba8f0cb438a5ba90a48ff55cb7cb |