测试覆盖率可视化 (FREE)
借助极狐GitLab CI/CD,您可以收集您喜欢的测试或覆盖率分析工具的测试覆盖信息,并在合并请求 (MR) 的文件差异视图中可视化此信息。允许您在合并 MR 之前查看哪些行被测试覆盖,哪些行仍然需要覆盖。
测试覆盖率可视化工作原理
收集覆盖信息是通过极狐GitLab CI/CD 的产物报告功能完成的。 您可以指定一个或多个要收集的覆盖报告,包括通配符路径。 然后系统获取所有文件中的覆盖信息并将其组合在一起。覆盖文件在后台作业中解析,因此从流水线完成到页面上的可视化加载之间可能存在延迟。
为了使覆盖分析起作用,您必须向 artifacts:reports:coverage_report 提供格式正确的 Cobertura XML 报告。
这种格式最初是为 Java 开发的,但大多数其它语言的覆盖分析框架都有插件来添加对它的支持,例如:
- simplecov-cobertura (Ruby)
- gocover-cobertura (Golang)
其它覆盖分析框架支持开箱即用的格式,例如:
- Istanbul (JavaScript)
- Coverage.py (Python)
- PHPUnit (PHP)
配置后,如果您创建一个触发收集覆盖率报告的流水线的合并请求,则覆盖率将显示在差异视图中,包括来自流水线中任何阶段的任何作业的报告。每行的覆盖率显示如下:
-
covered(绿色):通过测试至少检查过一次的行 -
no test coverage(橙色):已加载但从未执行的行 - 无覆盖信息:未插入或未加载的行
将鼠标悬停在覆盖栏上可提供更多信息,例如测试检查代码行的次数。
上传测试覆盖率报告不会启用:
您必须单独配置这些。
限制
Cobertura 格式 XML 文件的 100 个 <source> 节点的限制适用。如果您的 Cobertura 报告超过 100 个节点,则合并请求差异视图中可能存在不匹配或无匹配。
单个 Cobertura XML 文件不能超过 10MiB。对于大型项目,将 Cobertura XML 拆分为较小的文件。 提交许多文件时,可能需要几分钟才能在合并请求中显示覆盖范围。
可视化仅在流水线完成后显示。如果流水线有阻塞的手动作业,则流水线在继续之前等待手动作业,并且不被视为完成。 如果阻塞的手动作业未运行,则无法显示可视化。
产物过期
默认情况下,用于在合并请求上绘制可视化的流水线产物在创建后一周过期。
来自子流水线的覆盖率报告
- 引入于 15.1 版本,功能标志为
ci_child_pipeline_coverage_reports,默认禁用。- 在 SaaS 版和私有化部署版上启用于 15.2 版本,功能标志
ci_child_pipeline_coverage_reports已删除。
如果子流水线中的作业创建了覆盖率报告,则该报告将包含在父流水线的覆盖率报告中。
child_test_pipeline:
trigger:
include:
- local: path/to/child_pipeline_with_coverage.yml
自动类路径校正
- 引入于 13.8 版本。
- 功能标志移除于 13.9 版本。
只有当 class 元素的 filename 包含相对于项目根目录的完整路径时,覆盖率报告才能正确匹配更改的文件。但是,在某些覆盖分析框架中,生成的 Cobertura XML 具有相对于类包目录的 filename 路径。
为了对项目根相对 class 路径做出明智的猜测,Cobertura XML 解析器尝试通过以下方式构建完整路径:
- 从
sources元素中提取部分source路径,并将它们与类filename路径组合。 - 检查项目中是否存在候选路径。
- 使用匹配的第一个候选者作为类完整路径。
路径校正示例
例如,一个项目具有:
-
test-org/test-project的完整路径。 -
与项目根目录相关的以下文件:
Auth/User.cs Lib/Utils/User.cs src/main/java
位于:
-
Cobertura XML 中,
class元素中的filename属性假定该值是项目根目录的相对路径:<class name="packet.name" filename="src/main/java" line-rate="0.0" branch-rate="0.0" complexity="5"> -
来自 Cobertura XML 的
sources,格式为<CI_BUILDS_DIR>/<PROJECT_FULL_PATH>/...的以下路径:<sources> <source>/builds/test-org/test-project/Auth</source> <source>/builds/test-org/test-project/Lib/Utils</source> </sources>
解析器:
- 从
sources中提取Auth和Lib/Utils并使用它们来确定相对于项目根目录的class路径。 - 结合这些提取的
sources和类文件名。例如,有一个class元素的filename值为User.cs,则解析器会采用第一个匹配的候选路径,即Auth/User.cs。 - 对于每个
class元素,尝试为每个提取的source路径查找匹配项,最多 100 次迭代。如果在文件树中没有找到匹配的路径就达到了这个限制,那么这个类就不会包含在最终的覆盖率报告中。
NOTE:
自动类路径更正仅适用于格式为 <CI_BUILDS_DIR>/<PROJECT_FULL_PATH>/... 的 source 路径。
如果路径不遵循此模式,则忽略 source。解析器假定 class 元素的 filename 包含相对于项目根目录的完整路径。
示例测试覆盖率配置
本节提供不同编程语言的测试覆盖率配置示例。
JavaScript 示例
以下 .gitlab-ci.yml 示例使用 Mocha JavaScript 测试和 nyc 覆盖率工具生成覆盖率产物:
test:
script:
- npm install
- npx nyc --reporter cobertura mocha
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
Java and Kotlin 示例
Maven 示例
以下用于 Java 或 Kotlin 的 .gitlab-ci.yml 示例使用 Maven 来构建项目和 JaCoCo 覆盖率工具来生成覆盖率产物。
极狐GitLab 需要 Cobertura 格式的产物,因此您必须在上传之前执行一些脚本。test-jdk11 作业测试代码并生成 XML 工件。coverage-jdk-11 作业将产物转换为 Cobertura 报告:
test-jdk11:
stage: test
image: maven:3.6.3-jdk-11
script:
- mvn $MAVEN_CLI_OPTS clean org.jacoco:jacoco-maven-plugin:prepare-agent test jacoco:report
artifacts:
paths:
- target/site/jacoco/jacoco.xml
coverage-jdk11:
# Must be in a stage later than test-jdk11's stage.
# The `visualize` stage does not exist by default.
# Please define it first, or choose an existing stage like `deploy`.
stage: visualize
image: registry.gitlab.com/haynes/jacoco2cobertura:1.0.7
script:
# convert report from jacoco to cobertura, using relative project path
- python /opt/cover2cover.py target/site/jacoco/jacoco.xml $CI_PROJECT_DIR/src/main/java/ > target/site/cobertura.xml
needs: ["test-jdk11"]
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: target/site/cobertura.xml
Gradle 示例
以下用于 Java 或 Kotlin 的 .gitlab-ci.yml 示例使用 Gradle 构建项目和 JaCoCo 覆盖率工具来生成覆盖率产物。
极狐GitLab 需要 Cobertura 格式的产物,因此您必须在上传之前执行一些脚本。test-jdk11 作业测试代码并生成 XML 产物。coverage-jdk-11 作业将产物转换为 Cobertura 报告:
test-jdk11:
stage: test
image: gradle:6.6.1-jdk11
script:
- 'gradle test jacocoTestReport' # jacoco must be configured to create an xml report
artifacts:
paths:
- build/jacoco/jacoco.xml
coverage-jdk11:
# Must be in a stage later than test-jdk11's stage.
# The `visualize` stage does not exist by default.
# Please define it first, or chose an existing stage like `deploy`.
stage: visualize
image: registry.gitlab.com/haynes/jacoco2cobertura:1.0.7
script:
# convert report from jacoco to cobertura, using relative project path
- python /opt/cover2cover.py build/jacoco/jacoco.xml $CI_PROJECT_DIR/src/main/java/ > build/cobertura.xml
needs: ["test-jdk11"]
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: build/cobertura.xml
Python 示例
以下 Python 的 .gitlab-ci.yml 示例使用 pytest-cov 收集测试覆盖率数据,coverage.py 将报告转换为使用完整的相对路径。没有转换就不会显示信息。
此示例假设您的包的代码在 src/ 中并且您的测试在 tests.py 中:
run tests:
stage: test
image: python:3
script:
- pip install pytest pytest-cov
- coverage run -m pytest
- coverage report
- coverage xml
coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/'
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage.xml
PHP 示例
以下 PHP 的 .gitlab-ci.yml 示例使用 PHPUnit 来收集测试覆盖率数据并生成报告。
使用最小的 phpunit.xml 文件,您可以运行测试并生成 coverage.xml:
run tests:
stage: test
image: php:latest
variables:
XDEBUG_MODE: coverage
before_script:
- apt-get update && apt-get -yq install git unzip zip libzip-dev zlib1g-dev
- docker-php-ext-install zip
- pecl install xdebug && docker-php-ext-enable xdebug
- php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
- php composer-setup.php --install-dir=/usr/local/bin --filename=composer
- composer install
- composer require --dev phpunit/phpunit phpunit/php-code-coverage
script:
- php ./vendor/bin/phpunit --coverage-text --coverage-cobertura=coverage.cobertura.xml
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage.cobertura.xml
Codeception,通过 PHPUnit,也支持用 run 生成 Cobertura 报告。生成文件的路径取决于单元测试套件的 --coverage-cobertura 选项和 paths 配置。配置 .gitlab-ci.yml 在适当的路径中找到 Cobertura。
C/C++ 示例
以下 .gitlab-ci.yml 示例适用于带有 gcc 或 g++ 的 C/C++,因为编译器使用 gcovr 生成 Cobertura XML 格式的覆盖率输出文件。
此示例假设:
-
Makefile是在前一阶段的另一个作业中,由cmake在build目录中创建的。(如果使用automake生成Makefile,则需要调用make check而不是make test。) -
cmake(或automake)设置了编译器选项--coverage。
run tests:
stage: test
script:
- cd build
- make test
- gcovr --xml-pretty --exclude-unreachable-branches --print-summary -o coverage.xml --root ${CI_PROJECT_DIR}
coverage: /^\s*lines:\s*\d+.\d+\%/
artifacts:
name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}
expire_in: 2 days
reports:
coverage_report:
coverage_format: cobertura
path: build/coverage.xml
Go 示例
以下 Go 使用的 .gitlab-ci.yml 示例:
-
go test运行测试。 -
gocover-cobertura将 Go 的覆盖率配置文件转换为 Cobertura XML 格式。
此示例假定正在使用 Go 模块。请注意,-covermode count 选项不适用于 -race 标志。
如果您想在使用 -race 标志的同时生成代码覆盖率,则必须切换到比 -covermode count 慢的-covermode atomic。有关详细信息,请参阅 此博客文章。
run tests:
stage: test
image: golang:1.17
script:
- go install
- go test ./... -coverprofile=coverage.txt -covermode count
- go get github.com/boumenot/gocover-cobertura
- go run github.com/boumenot/gocover-cobertura < coverage.txt > coverage.xml
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage.xml
Ruby 示例
以下用于 Ruby 的 .gitlab-ci.yml 示例使用:
-
rspec运行测试。 -
simplecov和simplecov-cobertura记录覆盖率概况以及创建 Cobertura XML 格式的报告。
此示例假设:
-
bundler被用于依赖管理。rspec、simplecov和simplecov-coberturagem 已添加到您的Gemfile中。 -
CoberturaFormatter已添加到spec_helper.rb文件中的SimpleCov.formatters配置中。
run tests:
stage: test
image: ruby:3.1
script:
- bundle install
- bundle exec rspec
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage/coverage.xml
故障排除
未显示测试覆盖率可视化
如果测试覆盖率可视化未显示在差异视图中,您可以检查覆盖率报告本身并验证:
- 您在差异视图中查看的文件在覆盖率报告中提及。
- 报告中的
source和filename节点遵循预期结构,匹配仓库中的文件。
默认情况下,报告产物不可下载。如果您希望可以从作业详细信息页面下载报告,请将您的覆盖率报告添加到产物 paths 中:
artifacts:
paths:
- coverage/cobertura-coverage.xml
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
