在 Azure Pipelines 中查看和配置代码覆盖率结果

Azure DevOps Services |Azure DevOps Server |Azure DevOps Server 2022 |Azure DevOps Server 2020

代码覆盖率有助于确定实际测试的项目代码的比例,例如通过单元测试。 为了增强对代码更改的信任并有效防范 bug,测试应全面覆盖或模拟大部分代码。

查看代码覆盖率结果时,可以识别测试未涵盖的代码路径。 此信息可减少测试债务,从而帮助你随时间推移提高测试覆盖率。

本文介绍如何在 Azure Pipelines 中查看、配置和排查代码覆盖率问题。 了解如何为拉取请求设置差异覆盖范围、配置覆盖率策略并解决常见问题。

注意

虽然可以从 Azure Pipelines 支持的各种版本控制系统生成代码,但本文中讨论的拉取请求功能的代码覆盖率目前仅适用于 Azure Repos。

支持的格式、任务和工件

支持的格式

Azure Pipelines 可以通过发布代码覆盖率结果 v2 任务发布覆盖率结果。 该任务可以在 2 个不同的视图中显示结果:

  • 对于 cobertura、jacoco、clover、gcov、pcov 和其他 xml 格式,HTML 视图生成,其中包含代码覆盖率报表的更多详细信息,并且大多数客户都首选。
  • 对于 .coverage/.cjson/.covx – 表格视图生成,包含的详细信息小于 HTML 视图。

项目和结果

可以在管道运行概要的摘要选项卡下查看生成过程中发布的代码覆盖率工件。

屏幕截图显示了“摘要”选项卡,其中包含手动运行和 2 个已发布的项目。

此外,还可以在 “代码覆盖率 ”选项卡中查看代码覆盖率报告的结果:

屏幕截图显示“代码覆盖率”选项卡内容,其中包含摘要、指标和覆盖范围。

  • 如果使用 Cobertura 或 JaCoCo 覆盖率格式发布代码覆盖率结果,则代码覆盖率项目包含一个文件.html,可脱机查看以供进一步分析。 显示 HTML 报表摘要的屏幕截图。
  • 对于 .NET 和 .NET Core,可以通过在生成摘要中选择代码覆盖率里程碑来访问下载项目的链接。
  • Visual Studio Test 可以收集 .NET 和 .NET Core 应用的覆盖范围。 它生成的 .coverage 文件可供下载并在 Visual Studio 中用于进一步分析。 屏幕截图显示了代码覆盖率结果。

任务

发布代码覆盖率结果 会将代码覆盖率结果发布到 Azure Pipelines,这些结果是由生成步骤以 CoberturaJaCoCo 格式生成的。

Visual Studio 测试.NET CoreAntMavenGulpGruntGradle 等内置任务还提供将代码覆盖率数据发布到管道的选项。

Docker 注意事项

对于使用 Docker 的应用,可以在容器内运行生成和测试,并在容器内生成代码覆盖率结果。 若要将结果发布到管道,请使生成的项目可用于 “发布代码覆盖率结果 ”任务。 作为参考,请参阅 Docker 的 生成、测试和发布结果 部分下发布测试结果的类似示例。

重要注意事项

  • 在多阶段 YAML 管道中,代码覆盖率结果仅在整个管道完成后可用。 如果要在部署到生产环境之前查看代码覆盖率结果,可能需要将构建阶段划分为独立的流水线。
  • 合并多个测试运行的代码覆盖率结果目前仅适用于 .NET 和 .NET Core。 没有支持其他格式的计划。

完整覆盖范围与差异覆盖率

完整覆盖 度量项目的整个代码库的覆盖面。 在拉取请求的上下文中,开发人员专注于所做更改,并想知道他们添加或更改的特定代码行是否包括在内。 这种类型的覆盖率是差异覆盖率

覆盖设置 YAML 不同于 YAML 管道,因为覆盖设置适用于存储库,并且无论哪个管道生成代码,都会使用。 如果您使用经典的设计器构建管道,这种分离还意味着您可以为拉取请求获取代码覆盖率状态检查。

无论是否启用拉取请求注释详细信息,覆盖指示器都会显示在已更改文件视图中。

配置差异覆盖范围

若要更改拉取请求代码覆盖率体验的默认设置,请在存储库根目录包含一个名为 azurepipelines-coverage.yml 的配置 YAML 文件。 设置此文件中的所需值,Azure DevOps 会在下次管道运行时自动使用这些值。

您可以更改以下设置:

屏幕截图显示了可以配置的设置。

示例配置

coverage:  
  status:                    # Code coverage status will be posted to pull requests based on targets defined below. 
    comments: on             # Off by default. When on, details about coverage for each file changed will be posted as a pull request comment.  
    diff:                    # Diff coverage is code coverage only for the lines changed in a pull request. 
      target: 60%            # Set this to a desired percentage. Default is 70 percent 

可以在 代码覆盖率 YAML 示例存储库中找到包含详细信息的更多示例。

覆盖率状态、详细信息和指示符

设置管道以收集和发布代码覆盖率时,它会在创建拉取请求时发布代码覆盖率状态。 默认情况下,服务器检查测试是否涵盖至少 70% 的已更改行。 可以通过修改前面提到的目标参数,将差异覆盖率阈值目标更改为所选值。

屏幕截图显示覆盖状态检查失败。

状态检查计算拉取请求中所有文件的差异覆盖率。 若要查看每个文件的百分比,请启用“详细信息”,如上一部分所述。 启用后,系统会将详细信息作为对拉取请求的注释发布。

屏幕截图显示了差异覆盖率检查失败的结果。

在拉取请求的已更改文件视图中,更改的行还标注了覆盖率指示器,以显示这些行是否被覆盖。

屏幕截图显示了拉取请求行更改覆盖率指示器。

使用代码覆盖率策略强制实施分支保护

默认情况下,Pull Request 的代码覆盖率状态检查是建议的 - 即使覆盖率低的情况下也不会阻止合并。 若要在合并之前确保更改满足最低覆盖阈值,请配置使用覆盖范围状态检查的分支策略。

从管道发布的代码覆盖率状态遵循命名约定 {name-of-your-pipeline/codecoverage}

注意

  • Azure Repos 中的分支策略(甚至是可选策略)会阻止拉取请求在失败时自动完成。 此行为不特定于代码覆盖率策略。
  • 如果构建失败,代码覆盖率策略不会被设置为“失败”。

故障排除指南

为什么我在“代码覆盖率”选项卡的覆盖视图中会看到重复的 DLL?

管道中使用 .NET Core 和 .NET Framework 时,可能会看到重复的 DLL。 预计在同时使用两者时,会出现重复的 DLL,这是设计使然,因为相同的模块来自不同的路径。

为什么“代码覆盖率”选项卡中没有覆盖率数据?

多种原因可能会导致此问题:

  • 不存在测试或 DLL:如果文件不包含测试或 DLL,则覆盖率值为 0。 当覆盖率值为 0 时,Azure DevOps 不会在选项卡中显示代码覆盖率数据。 而是在“代码覆盖率”选项卡下显示一条消息,说明为何没有覆盖率数据。

  • 空覆盖率 XML:使用“发布代码覆盖率”任务时,如果作为输入提供的覆盖率 .xml 不包含任何信息或未覆盖零行,则选项卡下不会显示任何覆盖数据。请检查覆盖率 .xml 文件(输入文件)为何为空或缺少信息。

  • 生成失败:如果生成失败,则代码覆盖率选项卡会显示相应的消息。

  • VSTest 任务配置:使用 VSTest 任务时,如果未启用代码覆盖率检查,或者提到不正确的 DLL 或测试筛选器字段中测试文件的路径不正确,则不会显示覆盖率数据。

  • 生成配置问题:有时存在多个生成配置值,并且未设置所有值,如 BuildFlavour 或 BuildPlatform。 UI 仅显示特定生成配置的值,这就是为什么缺少其他模块的原因。

  • 大型 HTML 文件:如果 .html 文件大于 7 MB,则报表在“代码覆盖率”选项卡中不可用。解决方法是从摘要中已发布的项目下载“代码覆盖率Report_*”项目。

  • 失败消息:如果“代码覆盖率”选项卡包含与用户特定的错误相关的失败消息,请调查触发该错误消息的内容。

如果代码覆盖率状态检查从未完成或失败,该怎么办?

若要启用代码覆盖率状态检查,请尝试在 azurepipelines-coverage.yml 存储库的根目录中添加该文件。 确保文件名保持不变。 下面是一个示例:

coverage: 
  status: 
    comments: on 
    diff: 
      target: 50% 

如果覆盖状态检查失败:

  1. 检查差异覆盖率百分比。 如果它小于目标,请尝试增加差异覆盖率百分比。
  2. 如果生成因任何原因而失败,则此失败也可能导致代码覆盖率状态检查失败。
  3. 检查哪个任务在管道中生成覆盖文件或报告。 验证任务是否正确上传覆盖率报告或文件。
  4. 差异覆盖率注释显示“未找到可执行更改”或“未找到代码覆盖率数据”的情形可能会由于代码行被删除、空白字符的引入或添加注释而发生。 这些情况是不可执行的更改,并不重要,因此代码覆盖率不会报告它们。

如何从代码覆盖率中排除某些 DLL?

若要从代码覆盖率中排除文件,请使用 ExcludeFromCodeCoverageAttribute 类

如何通过合并多个摘要文件来发布代码覆盖率摘要以及适当的详细信息?

发布代码覆盖率 V1 任务不支持多个摘要文件作为输入。 请改为使用发布代码覆盖率 V2 任务,该任务支持多种文件格式。

还可以使用 报表生成器任务 合并所有 .xml 文件,然后将生成的 XML 路径作为输入传递给发布代码覆盖率任务。

如何启动代码覆盖率检查?

对于 .html 文件,不支持覆盖率状态检查。 使用 生成质量检查任务 检查代码覆盖率结果。

“代码覆盖率”选项卡上的报告包含不准确的数字

选项卡上显示的数据是来自覆盖率文件。 如果使用自定义任务生成代码覆盖率文件,请检查该文件是否缺少任何 DLL 或文件。

代码覆盖率策略卡住——原因是什么?

多种因素可能导致此问题:

  • 分支策略名称格式不正确:验证管道名称是否与分支策略名称匹配,并且没有额外的字符。

    屏幕截图显示“策略”选项卡和突出显示的分支策略名称,以确认它与管道名称匹配。

  • 使用 PublishCodeCoverage V1:代码覆盖率策略停滞,不会生成注释。 请使用 PublishCodeCoverage V2 任务代替。

  • PR 中的文件过多:如果 PR 有 100 多个文件,则覆盖策略会停滞。

  • 多个覆盖策略:如果配置多个覆盖策略,其中一个策略会停滞不前。 仅配置一个策略并删除另一个停滞的策略。

即使添加了测试,我的 PR 的差异覆盖率仍然是 0%。

如果添加测试以涵盖 PR 中已修改的代码行或新代码行,但仍会看到 0% 差异覆盖率:

  1. 验证新添加的测试是否在生成过程中运行。
  2. 如果测试未运行,请验证并更新配置以将其包含在生成中,因为测试未运行时无法计算覆盖率。

即使我能看到覆盖率报告发布,但我在 PR 上没有看到差异覆盖率的评论。

多种因素可能导致此问题:

  • 任务版本:仅发布代码覆盖率 V2 支持差异覆盖率注释。
  • 无可执行更改:为具有可执行代码更改的文件生成差异覆盖率注释。 如果 PR 仅包含配置更新,Azure DevOps 可能会根据构建过程中运行的所有测试显示代码覆盖率,但可能没有任何变更覆盖率可计算。
  • 覆盖率格式:如果存在功能代码更改且注释未生成,请验证管道是否以本文开头提到的支持格式之一生成覆盖报告。

在“代码覆盖率”选项卡中,看不到正确的 HTML 报表

生成报表.html时出现问题,系统会切换到简化的视图。

屏幕截图显示了“代码覆盖率”选项卡、模块列表以及覆盖率图表的可视指示器,这是回退简化视图。

哪些覆盖率工具和结果格式可用于验证拉取请求中的代码覆盖率?

目前,只能使用 Visual Studio Code 覆盖率(.coverage)格式来验证拉取请求的代码覆盖率。 如果你使用 Visual Studio 的测试任务、.NET Core 任务的 test 动作和发布测试结果任务的 TRX 选项来发布代码覆盖率,请使用这种格式。

如果在提出拉取请求时触发了多个管道,覆盖率是否会在各管道间合并?

如果在引发拉取请求时触发了多个管道,则代码覆盖率不会合并。 此功能目前专为单个管道设计,用于收集并发布拉取请求的代码覆盖率。 如果需要跨管道合并覆盖率数据,请在开发人员社区上提交功能请求。