Help us learn about your current experience with the documentation. Take the survey.

Cobertura 覆盖率报告

  • 版本:免费、专业、旗舰
  • 产品形态:GitLab.com、GitLab 自管版、GitLab 专属版

要使覆盖率分析正常工作,您需要提供一个格式正确的 Cobertura XML 报告给 artifacts:reports:coverage_report。 该格式最初是为 Java 开发的,但现在大多数其他语言和平台的覆盖率分析框架都提供了插件来支持它,例如:

另一些覆盖率分析框架则原生支持该格式,例如:

配置完成后,如果您的合并请求触发了收集覆盖率报告的流水线,覆盖率信息便会显示在差异视图中。 这包括流水线中任何阶段、任何作业的报告。每行代码的覆盖率显示如下:

  • covered(绿色):已被测试至少执行一次的代码行
  • no test coverage(橙色):已加载但从未执行的代码行
  • 无覆盖率信息:未被插桩或未加载的代码行

将鼠标悬停在覆盖率条上可以查看更多信息,例如该行被测试执行的次数。

上传测试覆盖率报告不会自动启用:

您需要单独配置这些功能。

限制

Cobertura 格式的 XML 文件有 100 个 <source> 节点的限制。如果您的 Cobertura 报告超过 100 个节点,合并请求的差异视图中可能会出现匹配错误或无法匹配的情况。

单个 Cobertura XML 文件大小不能超过 10 MiB。对于大型项目,请将 Cobertura XML 文件拆分为 更小的文件。更多详情请参阅 此 issue。 当提交多个文件时,覆盖率在合并请求上显示可能需要几分钟时间。

覆盖率可视化仅在流水线完成后才会显示。如果流水线包含一个 阻塞式手动作业,流水线会等待该手动作业完成后才能继续,因此不被视为已完成。 如果阻塞式手动作业未运行,则无法显示覆盖率可视化。

如果作业生成了多个报告,请在构件路径中使用通配符

自动类路径修正

只有当 class 元素中的 filename 包含相对于项目根目录的完整路径时,覆盖率报告才能正确匹配已更改的文件。 然而,在某些覆盖率分析框架中,生成的 Cobertura XML 中的 filename 路径是相对于类包目录的,而不是项目根目录。

为了智能地推断出相对于项目根目录的 class 路径,Cobertura XML 解析器会尝试通过以下方式构建完整路径:

  • sources 元素中提取部分 source 路径,并与类 filename 路径结合。
  • 检查候选路径是否存在于项目中。
  • 使用第一个匹配的候选路径作为类的完整路径。

路径修正示例

例如,一个 C# 项目,其:

  • 完整路径为 test-org/test-cs-project

  • 相对于项目根目录的文件如下:

    Auth/User.cs
    Lib/Utils/User.cs
  • 来自 Cobertura XML 的 sources,其路径格式为 <CI_BUILDS_DIR>/<PROJECT_FULL_PATH>/...

    <sources>
      <source>/builds/test-org/test-cs-project/Auth</source>
      <source>/builds/test-org/test-cs-project/Lib/Utils</source>
    </sources>

解析器会:

  • sources 中提取 AuthLib/Utils,并用它们来确定相对于项目根目录的 class 路径。
  • 将这些提取的 sources 与类文件名结合。例如,如果存在一个 filename 值为 User.csclass 元素,解析器会采用第一个匹配的候选路径,即 Auth/User.cs
  • 对于每个 class 元素,会尝试为每个提取的 source 路径寻找匹配项,最多迭代 100 次。如果达到此限制仍未在文件树中找到匹配路径,则该类不会包含在最终的覆盖率报告中。

自动类路径修正同样适用于具有以下特征的 Java 项目:

  • 完整路径为 test-org/test-java-project

  • 相对于项目根目录的文件如下:

    src/main/java/com/gitlab/security_products/tests/App.java
  • 来自 Cobertura XML 的 sources

    <sources>
      <source>/builds/test-org/test-java-project/src/main/java/</source>
    </sources>
  • class 元素,其 filename 值为 com/gitlab/security_products/tests/App.java

    <class name="com.gitlab.security_products.tests.App" filename="com/gitlab/security_products/tests/App.java" line-rate="0.0" branch-rate="0.0" complexity="6.0">

自动类路径修正仅对格式为 <CI_BUILDS_DIR>/<PROJECT_FULL_PATH>/...source 路径有效。 如果路径不符合此模式,source 将被忽略。解析器假定 class 元素中的 filename 包含相对于项目根目录的完整路径。

测试覆盖率配置示例

本节提供了不同编程语言的测试覆盖率配置示例。您也可以在 coverage-report 演示项目中查看一个可运行的示例。

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 和 Kotlin 示例

Maven 和 Gradle 示例将 JaCoCo 报告转换为 Cobertura 格式。 或者,issue 227345 跟踪了启用原生 JaCoCo 报告支持的工作。

Maven 示例

以下适用于 Java 或 Kotlin 的 .gitlab-ci.yml 示例使用 Maven 来构建项目,并使用 JaCoCo 覆盖率工具来 生成覆盖率构件。 如果您想构建自己的镜像,可以查看 Docker 镜像配置和脚本

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:
  # 所处阶段必须晚于 test-jdk11 的阶段。
  # `visualize` 阶段默认不存在。
  # 请先定义它,或选择一个现有的阶段,如 `deploy`。
  stage: visualize
  image: registry.gitlab.com/haynes/jacoco2cobertura:1.0.9
  script:
    # 使用相对项目路径将报告从 jacoco 转换为 cobertura
    - 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 覆盖率工具来 生成覆盖率构件。 如果您想构建自己的镜像,可以查看 Docker 镜像配置和脚本

GitLab 期望构件是 Cobertura 格式,因此在上传前您需要执行一些 脚本。test-jdk11 作业负责测试代码并生成一个 XML 构件。 coverage-jdk-11 作业则将该构件转换为 Cobertura 报告:

test-jdk11:
  stage: test
  image: gradle:6.6.1-jdk11
  script:
    - 'gradle test jacocoTestReport' # 必须配置 jacoco 以创建 xml 报告
  artifacts:
    paths:
      - build/jacoco/jacoco.xml

coverage-jdk11:
  # 所处阶段必须晚于 test-jdk11 的阶段。
  # `visualize` 阶段默认不存在。
  # 请先定义它,或选择一个现有的阶段,如 `deploy`。
  stage: visualize
  image: registry.gitlab.com/haynes/jacoco2cobertura:1.0.7
  script:
    # 使用相对项目路径将报告从 jacoco 转换为 cobertura
    - 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 示例

以下 .gitlab-ci.yml 示例使用 pytest-cov 来收集测试覆盖率数据:

run tests:
  stage: test
  image: python:3
  script:
    - pip install pytest pytest-cov
    - pytest --cov --cov-report term --cov-report xml:coverage.xml
  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++ 示例

以下适用于 C/C++ 并使用 gccg++ 作为编译器的 .gitlab-ci.yml 示例,使用 gcovr 来生成 Cobertura XML 格式的覆盖率输出文件。

此示例假设:

  • Makefile 是由 cmakebuild 目录中生成的, 该操作在上一阶段的另一个作业中完成。 (如果您使用 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}
  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 modules-covermode count 选项与 -race 标志不兼容。 如果您想在启用 -race 标志的同时生成代码覆盖率,必须切换到 -covermode atomic,它比 -covermode count 慢。更多详情请参阅 此博客文章

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 示例使用

此示例假设:

  • 正在使用 bundler 进行依赖管理。 rspecsimplecovsimplecov-cobertura gem 已添加到您的 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

故障排除

未显示测试覆盖率可视化

如果差异视图中未显示测试覆盖率可视化,您可以检查 覆盖率报告本身,并确认以下几点:

  • 您在差异视图中查看的文件在覆盖率报告中被提及。
  • 报告中的 sourcefilename 节点遵循预期的结构,以匹配您仓库中的文件。
  • 流水线已完成。如果流水线被手动作业阻塞,则不被视为已完成。
  • 覆盖率报告文件未超出限制

报告构件默认不可下载。如果您希望报告可以从作业详情页面下载,请将您的覆盖率报告添加到构件 paths 中:

artifacts:
  paths:
    - coverage/cobertura-coverage.xml
  reports:
    coverage_report:
      coverage_format: cobertura
      path: coverage/cobertura-coverage.xml