"一个Cobertura覆盖率解析器,可以比较报告并显示覆盖率进度。"
项目描述
pycobertura
Cobertura报告的代码覆盖率比较工具。
关于
pycobertura是一个通用的Cobertura报告解析器。它也被设计用来帮助防止代码覆盖率因pycobertura diff
命令而降低:任何更改的行都应该经过测试,未被覆盖的更改应该清晰地显示出来,以便开发人员可以专注于他们的更改,而不会让遗留的未覆盖代码阻碍。
特性
- 显示cobertura文件的覆盖率摘要
- 输出为纯文本或HTML
- 比较两个cobertura文件并显示覆盖率的变化
- 彩色diff输出
- 如果覆盖率下降或任何更改未被覆盖,则diff退出状态为非零
- 基于未覆盖的行而不是覆盖率率下降来失败(查看原因)
注意:API是不稳定的,可能直到达到1.0版本之前都会发生变化。
安装
pip install pycobertura
命令行使用
pycobertura提供了一条命令行接口pycobertura
来报告覆盖率文件。
此外,pycobertura还可以作为模块通过python -m pycobertura
调用,请参阅PEP 338。
帮助命令
根据您需要帮助的内容,不同的帮助屏幕可供选择。
$ pycobertura --help
Usage: pycobertura [OPTIONS] COMMAND [ARGS]...
Options:
--help Show this message and exit.
Commands:
diff The diff command compares and shows the changes between two...
show show coverage summary of a Cobertura report
pycobertura show --help
pycobertura diff --help
命令 show
show
命令显示覆盖率文件的报告摘要。
$ pycobertura show coverage.xml
Filename Stmts Miss Cover Missing
------------------------- ------- ------ ------- ---------
pycobertura/__init__.py 1 0 100.00%
pycobertura/cli.py 18 0 100.00%
pycobertura/cobertura.py 93 0 100.00%
pycobertura/reporters.py 129 0 100.00%
pycobertura/utils.py 12 0 100.00%
TOTAL 253 0 100.00%
注意:由于默认的csv格式中我们选择了分号作为分隔符,因为在“缺少”列中内部使用的是分号,因此逗号分隔符可能会导致在编辑器中渲染csv时出现问题。
$ pycobertura show --format csv coverage.xml --delimiter ";"
Filename;Stmts;Miss;Cover;Missing
pycobertura/__init__.py;2;0;100.00%;
pycobertura/cli.py;132;88;33.33%;274-3758
pycobertura/cobertura.py;216;35;83.80%;423, 648-696
pycobertura/filesystem.py;91;6;93.41%;343-625
pycobertura/reporters.py;214;110;48.60%;291, 295-3284
pycobertura/utils.py;122;15;87.70%;38, 262-486
pycobertura/templates/__init__.py;0;0;100.00%;
pycobertura/templates/filters.py;17;10;41.18%;261-544
TOTAL;794;264;66.75%;
$ pycobertura show --format markdown coverage.xml
| Filename | Stmts | Miss | Cover | Missing |
|-----------------------------------|---------|--------|---------|--------------------|
| pycobertura/__init__.py | 2 | 0 | 100.00% | |
| pycobertura/cli.py | 132 | 88 | 33.33% | 274-3758 |
| pycobertura/cobertura.py | 216 | 35 | 83.80% | 423, 648-696 |
| pycobertura/filesystem.py | 91 | 6 | 93.41% | 343-625 |
| pycobertura/reporters.py | 222 | 114 | 48.65% | 286, 290, 331-4065 |
| pycobertura/utils.py | 122 | 15 | 87.70% | 38, 262-486 |
| pycobertura/templates/__init__.py | 0 | 0 | 100.00% | |
| pycobertura/templates/filters.py | 17 | 10 | 41.18% | 261-544 |
| TOTAL | 802 | 268 | 66.58% | |
以下是一张另一覆盖率文件的HTML版本的截图,该文件还包含了带有突出显示源代码的源代码,以指示行是否被覆盖(绿色)或未覆盖(红色)。
pycobertura show --format html --output coverage.html coverage.xml
以下展示了如何生成另一覆盖率文件的JSON版本。
$ pycobertura show --format json --output coverage.json tests/cobertura.xml
{
"files": [
{
"Filename": "Main.java",
"Stmts": 15,
"Miss": 0,
"Cover": "100.00%",
"Missing": ""
},
{
"Filename": "search/BinarySearch.java",
"Stmts": 12,
"Miss": 1,
"Cover": "91.67%",
"Missing": "24"
},
{
"Filename": "search/ISortedArraySearch.java",
"Stmts": 0,
"Miss": 0,
"Cover": "100.00%",
"Missing": ""
},
{
"Filename": "search/LinearSearch.java",
"Stmts": 7,
"Miss": 2,
"Cover": "71.43%",
"Missing": "19-24"
}
],
"total": {
"Filename": "TOTAL",
"Stmts": 34,
"Miss": 3,
"Cover": "90.00%"
}
}
$ pycobertura show --format yaml --output coverage.yaml tests/cobertura.xml
files:
- Filename: Main.java
Stmts: 15
Miss: 0
Cover: 100.00%
Missing: ''
- Filename: search/BinarySearch.java
Stmts: 12
Miss: 1
Cover: 91.67%
Missing: '24'
- Filename: search/ISortedArraySearch.java
Stmts: 0
Miss: 0
Cover: 100.00%
Missing: ''
- Filename: search/LinearSearch.java
Stmts: 7
Miss: 2
Cover: 71.43%
Missing: 19-24
total:
Filename: TOTAL
Stmts: 34
Miss: 3
Cover: 90.00%
以下展示了如何根据覆盖率文件生成GitHub注释。
$ pycobertura show --format github-annotation tests/cobertura.xml
::notice file=dummy/dummy.py,line=5,endLine=6,title=pycobertura::not covered
::notice file=dummy/dummy4.py,line=1,endLine=6,title=pycobertura::not covered
如果您在GitHub Actions/Apps中运行它,上述日志将生成检查注释。
命令 diff
您还可以使用diff
命令来显示两个覆盖率文件之间的差异。为了正确计算“缺少”列,必须提供生成每个传入Cobertura报告所使用的源代码(为什么需要提供源代码路径)。
$ pycobertura diff coverage.old.xml coverage.new.xml --source1 old_source/ --source2 new_source/
Filename Stmts Miss Cover Missing
---------------- ------- ------ -------- ---------
dummy/dummy.py - -2 +50.00% -2, -5
dummy/dummy2.py +2 - +100.00%
TOTAL +2 -2 +50.00%
“缺少”列将显示带有加号+
或减号-
前缀的行号。当带有加号前缀时,该行被添加为未覆盖,以红色显示;当带有减号前缀时,该行不再未覆盖,以绿色显示。
类似地,您也可以通过以下方式以csv格式显示diff,并可以定义分隔符(\t也在这里有效):
pycobertura diff tests/dummy.source1/coverage.xml tests/dummy.source2/coverage.xml --format csv --delimiter ";"
注意:默认分隔符是分号 (;)。逗号 (,) 和换行 (/n) 分隔符非常危险,并且此库不支持。逗号分隔符在列表数据结构中的“缺少”列中用于分隔不同的项目。因此,逗号分隔符可能会导致在编辑器中渲染csv时出现问题。由于csv中的缺失值对应于空值,换行分隔符也可能导致在编辑器中渲染csv时出现问题。
类似地,您也可以通过以下方式以markdown格式显示diff:
pycobertura diff --format markdown tests/dummy.source1/coverage.xml tests/dummy.source2/coverage.xml
这将导致以下输出
此截图显示了HTML输出如何仅将覆盖率突出显示应用于代码中覆盖率已更改的部分(从被覆盖到未覆盖,或反之)。
pycobertura diff --format html --output coverage.html ./master/coverage.xml ./myfeature/coverage.xml
此截图显示了JSON输出如何仅将覆盖率突出显示应用于代码中覆盖率已更改的部分(从被覆盖到未覆盖,或反之)。
pycobertura diff --format json tests/dummy.source1/coverage.xml tests/dummy.source2/coverage.xml
此截图显示了YAML输出如何仅将覆盖率突出显示应用于代码中覆盖率已更改的部分(从被覆盖到未覆盖,或反之)。
pycobertura diff --format yaml tests/dummy.source1/coverage.xml tests/dummy.source2/coverage.xml
以下展示了如何根据覆盖率文件生成GitHub注释。
$ pycobertura diff --format github-annotation tests/dummy.source1/coverage.xml tests/dummy.source2/coverage.xml
::notice file=dummy/dummy2.py,line=5,endLine=5,title=pycobertura::not covered
::notice file=dummy/dummy3.py,line=1,endLine=2,title=pycobertura::not covered
如果您在GitHub Actions/Apps中运行它,上述日志将生成检查注释。
通过--ignore-regex选项排除文件
您可以通过指定.gitignore
文件的路径或输入Python正则表达式来指定--ignore-regex
选项以排除具有特定模式的文件。示例
pycobertura show tests/cobertura.xml
Filename Stmts Miss Cover Missing
------------------------------ ------- ------ ------- ---------
Main.java 15 0 100.00%
search/BinarySearch.java 12 1 91.67% 24
search/ISortedArraySearch.java 0 0 100.00%
search/LinearSearch.java 7 2 71.43% 19-24
TOTAL 34 3 90.00%
pycobertura show tests/cobertura.xml --ignore-regex ".*Search"
Filename Stmts Miss Cover Missing
---------- ------- ------ ------- ---------
Main.java 15 0 100.00%
TOTAL 34 3 90.00%
注意:仅输入
*
,例如“*Search”上方的操作将导致错误,您必须真正遵循Python正则表达式约定才能使用此选项。您也可以指定包含以下内容的.testgitignore
:
# Test file for ignore regexes
**/__pycache__
**/dummy*
*.xml
**/*Search*
然后使用
pycobertura show tests/cobertura.xml --ignore-regex "tests/.testgitignore"
Filename Stmts Miss Cover Missing
---------- ------- ------ ------- ---------
Main.java 15 0 100.00%
TOTAL 34 3 90.00%
同样的方法也适用于diff
命令。
diff
退出代码
退出时,diff
命令可能会返回各种退出代码
- 0:所有更改都已涵盖,没有引入新的未涵盖语句
- 1:发生了一些异常(可能是由于不当使用或pycobertura中的错误)
- 2:更改恶化了整体覆盖率
- 3:更改引入了未涵盖语句,但整体覆盖率仍然比之前更好
您可以通过使用shell中的$?
语法来捕获退出代码
pycobertura ...
PYCOBERTURA_EXIT_CODE=$?
echo $PYCOBERTURA_EXIT_CODE
库使用
将其作为Python应用程序中的库使用很容易
from pycobertura import Cobertura
cobertura = Cobertura('coverage.xml')
cobertura.version == '4.0.2'
cobertura.line_rate() == 1.0 # 100%
cobertura.files() == [
'pycobertura/__init__.py',
'pycobertura/cli.py',
'pycobertura/cobertura.py',
'pycobertura/reporters.py',
'pycobertura/utils.py',
]
cobertura.line_rate('pycobertura/cli.py') == 1.0
from pycobertura import TextReporter
tr = TextReporter(cobertura)
tr.generate() == """\
Filename Stmts Miss Cover Missing
------------------------- ------- ------ ------- ---------
pycobertura/__init__.py 1 0 100.00%
pycobertura/cli.py 18 0 100.00%
pycobertura/cobertura.py 93 0 100.00%
pycobertura/reporters.py 129 0 100.00%
pycobertura/utils.py 12 0 100.00%
TOTAL 253 0 100.00%"""
from pycobertura import TextReporterDelta
coverage1 = Cobertura('coverage1.xml')
coverage2 = Cobertura('coverage2.xml')
delta = TextReporterDelta(coverage1, coverage2)
delta.generate() == """\
Filename Stmts Miss Cover Missing
---------------- ------- ------ -------- ---------
dummy/dummy.py - -2 +50.00% -2, -5
dummy/dummy2.py +2 - +100.00%
TOTAL +2 -2 +50.00%"""
如何贡献?
发现了一个错误/打字错误?有一个补丁?有想法吗?请使用Github问题或fork pycobertura并提交一个拉取请求(PR)。所有贡献都受欢迎!
如果您提交PR
- 确保您的PR描述清楚地说明了您的更改,通过显示问题是什么以及您是如何解决的(之前/之后)
- 确保您的更改被一个或多个测试覆盖
- 在
Unreleased
部分下添加一个描述性注释到CHANGES文件 - 如果您的更改过时了文档,相应地更新README
- 确保所有测试都通过使用
tox
pip install tox
tox
常见问题解答
pycobertura是如何工作的?
Pycobertura取两个不同的Cobertura报告,逐行比较。如果某行从被覆盖变为未覆盖或相反,则pycobertura将报告它。有时您没有任何代码更改,唯一的变化是添加更多测试,pycobertura将向您展示进度。
Pycobertura最初被设计为一个通用Cobertura解析器,可以为单个Cobertura文件生成摘要表(show
命令)。
我只有一个Cobertura报告,我能否只看到我的未涵盖更改?
是的。您需要做的就是两次传递相同的覆盖率报告,并提供两个不同代码库的路径
pycobertura diff coverage.xml coverage.xml --source1 master/ --source2 myfeature/
但请注意,这不会显示您的更改是否在代码库的其他地方引入了覆盖率下降。
为什么pycobertura不使用git根据源给定的修订SHA而不是传递源代码路径来进行diff?
因为我们必须支持N个版本控制系统(VCS)。生成包含给定提交或分支名的源代码的目录很容易,因此pycobertura具有VCS感知性不是优先事项
git archive --prefix=source1/ ${BRANCH_OR_COMMIT1} | tar -xf -
git archive --prefix=source2/ ${BRANCH_OR_COMMIT2} | tar -xf -
pycobertura diff --source1 source1/ --source2 source2/ coverage1.xml coverage2.xml -o output.html
rm -rf source1/ source2/
Mercurial有hg archive
,Subversion有svn export
。这些是运行pycobertura diff
的简单预步骤。
此外,代码库在运行pycobertura时可能始终不可用。通常,在持续交付管道中,只有工件可用。
为什么我需要提供源代码目录的路径?
使用pycobertura show
命令时,您不需要提供源代码目录,除非您想要HTML输出,这将为您方便地渲染突出显示的源代码。
但使用pycobertura diff
,如果您关心哪些行被覆盖或未覆盖(而不仅仅是全局计数),则您将需要为每个报告提供源。
为了更好地理解原因,让我们假设我们有2个Cobertura报告,以下信息
报告A
line 1, hit
line 2, miss
line 3, hit
和报告B
line 1, hit
line 2, miss
line 3, hit
line 4, miss
line 5, hit
您如何知道哪些行需要突出显示?天真地,您会假设第4-5行被添加,并且这些应该是突出显示的行,是您的覆盖率差异的一部分。但这并不完全正确。
报告A的代码是
if foo is True: # line 1
total += 1 # line 2
return total # line 3
报告B的代码是
if foo is False: # line 1 # new line
total -= 1 # line 2 # new line
elif foo is True: # line 3 # modified line
total += 1 # line 4, unchanged
return total # line 5, unchanged
代码更改是第1-3行,这些是您想要突出显示的行。第4-5行不需要突出显示(除非覆盖状态在之间发生变化)。
因此,为了准确突出显示已更改的行,仅覆盖率报告是不够的,这就是为什么您需要提供用于生成每个Cobertura报告的源代码路径并对其进行diff以查看哪些行实际上已更改以报告准确的覆盖率。
我应该何时使用pycobertura?
pycobertura是一个旨在教育开发者测试文化的工具,其目的是确保任何代码更改都应该附带一个或多个测试。
您可以在您的持续集成(CI)或持续交付(CD)管道中使用pycobertura,如果代码更改降低了覆盖率,则会中断构建。例如,当提交拉取请求时,新代码的覆盖率应该与将要合并的分支相当或更好。或者,如果代码在发布管道中导航,并且新代码的覆盖率比生产环境中已有的覆盖率差,则发布将中断。
当您的CI/CD管道触发构建时,每个测试阶段通常会存储源代码的工件以及Cobertura报告的另一个工件。管道中的一个额外阶段可以确保覆盖率没有降低。这可以通过检索当前构建的工件以及“目标”工件(生产环境或拉取请求目标分支的代码和Cobertura报告)来实现。然后,pycobertura diff
将负责如果覆盖率降低则中断构建(返回非零退出代码),然后pycobertura报告可以作为工件发布,供开发人员查看。
这一步可能看起来是这样的
# Download artifacts of current build
curl -o coverage.${BUILD_ID}.xml https://ciserver/artifacts/${BUILD_ID}/coverage.xml
curl -o source.${BUILD_ID}.zip https://ciserver/artifacts/${BUILD_ID}/source.zip
# Download artifacts of already-in-Prod build
curl -o coverage.${PROD_BUILD}.xml https://ciserver/artifacts/${PROD_BUILD}/coverage.xml
curl -o source.${PROD_BUILD}.zip https://ciserver/artifacts/${PROD_BUILD}/source.zip
unzip source.${BUILD_ID}.zip -d source.${BUILD_ID}
unzip source.${PROD_BUILD}.zip -d source.${PROD_BUILD}
# Compare
pycobertura diff --format html \
--output pycobertura-diff.${BUILD_ID}.html \
--source1 source.${PROD_BUILD} \
--source2 source.${BUILD_ID} \
coverage.${PROD_BUILD}.xml \
coverage.${BUILD_ID}.xml
# Upload the pycobertura report artifact
curl -F filedata=@pycobertura-diff.${BUILD_ID}.html http://ciserver/artifacts/${BUILD_ID}/
为什么使用未覆盖行数而不是行率作为检查代码覆盖率是否降低的指标呢?
行率(已覆盖行的百分比)可能会因为多种原因而合法降低。为了说明,假设我们有我们代码版本A的此代码覆盖率报告
line 1: hit
line 2: hit
line 3: miss
line 4: hit
line 5: hit
在这里,行率是80%,未覆盖行数是1(遗漏)。稍后,在我们代码的版本B中,我们合法地删除了一个已覆盖的行,并生成了以下覆盖率报告
line 1: hit
### line deleted ###
line 2: miss
line 3: hit
line 4: hit
行率从80%下降到75%,但未覆盖行数仍然是1。在这种情况下,基于行率中断构建是不恰当的,因此行率不是验证覆盖率时应该考虑的正确指标。
基本思想是,代码库可能存在N行未覆盖的债务,您希望防止N行数上升。
pycobertura听起来不错,但我该如何生成Cobertura文件呢?
根据您的编程语言,您需要找到一个测量代码覆盖率并生成Cobertura报告的工具,这是代码覆盖率结果的XML表示。
在Python中,coverage.py是一个用于测量代码覆盖率的优秀工具,对于pytest的pytest-cov插件和nose的nosexcover插件都可用于在运行测试时生成Cobertura报告。
Istanbul可以为JavaScript生成Cobertura报告,并且还有CoffeeScript的插件,如果您喜欢的话。
Cobertura是一个非常常见的文件格式,在许多测试工具中可用,适用于几乎所有编程语言。pycobertura是语言无关的,应该可以与任何语言工具生成的报告一起使用。但它主要是在Python中的pytest-cov
插件生成的报告上进行开发和测试的。如果您发现问题,请创建一个工单。
标志归功于
pycobertura标志Aysha是由捐赠给Open Logos的。🙇 Check them out!
项目详情
下载文件
下载适合您平台的文件。如果您不确定选择哪个,请了解有关 安装包 的更多信息。