使用代码覆盖率确定所测试的代码量

若要确定正在由编码的测试(例如单元测试)进行测试的项目代码的比例,则可以使用 Visual Studio 的代码覆盖率功能。 若要有效防止 Bug,测试应作用于或“覆盖”你的大部分代码。

可将代码覆盖率分析应用于托管 (CLR) 和非托管(本机)代码。 支持静态和动态检测。 若要在命令行方案中使用代码覆盖率,请使用 vstest.console.exeMicrosoft.CodeCoverage.Console 工具,该工具是 dotnet-coverage 的扩展,也支持本机代码。

使用测试资源管理器运行测试方法时,代码覆盖率选项在“测试”菜单下可用。 结果表将显示在各个程序集、类和过程中运行的代码的百分比。 源编辑器突出显示测试的代码。 可以采用 Cobertura 等常用格式导出结果。

要求

代码覆盖率功能仅在 Visual Studio Enterprise 版本中可用。

注意

对于 .NET 代码覆盖率,也可以使用命令行工具 dotnet-coverage

分析代码覆盖率

  1. 在“测试”菜单中,选择“分析所有测试的代码覆盖率”

    突出显示了“分析代码覆盖率”的“测试”菜单的屏幕截图。

    突出显示了“分析代码覆盖率”的“测试”菜单的屏幕截图。

    提示

    你还可以从“测试资源管理器”工具窗口中运行代码覆盖率。

  2. 测试运行后,若要查看已运行的行,请选择“代码覆盖率结果”窗口Visual Studio 中“分析代码覆盖率”菜单的屏幕截图中的“显示代码覆盖率着色”。 默认情况下,测试覆盖的代码以浅蓝色突出显示。

    突出显示的代码覆盖率的屏幕截图。

    突出显示的代码覆盖率的屏幕截图。

    在“显示代码覆盖率着色”选项的下拉列表中,可以选择着色是否适用于代码行、左边距中的字形或两者。

  3. 要更改颜色或使用加粗,请选择“工具”>“选项”>“环境”>“字体和颜色”>“显示其设置: 文本编辑器”。 在“显示项”下,调整“覆盖率”项的设置,例如“覆盖率未涉及的区域”

    显示代码覆盖率字体和颜色的屏幕截图

    显示代码覆盖率字体和颜色的屏幕截图。

  4. 如果结果显示覆盖率较低,请调查代码的哪些部分没有执行测试,并编写更多测试来覆盖它们。 开发团队通常以大约 80% 的代码覆盖率为目标。 在某些情况下,较低的覆盖率是可接受的。 例如,当某代码是从标准模板生成时,可接受较低的覆盖率。

提示

若要优化代码覆盖率,请执行以下操作:

  • 关闭编译器优化。
  • 如果要处理非托管(本机)代码,请使用调试版本。
  • 为每个程序集生成 .pdb(符号)文件。

如果没有获得预期的结果,请参阅代码覆盖率疑难解答

不要忘记在更新代码后再次运行代码覆盖率。 在修改代码后或运行测试时,覆盖率结果和代码着色不会自动更新。

提示

从 Visual Studio 2022 Update 2 开始,可以通过选择“工具”>“选项”>“环境”>“预览功能”,然后选择“代码覆盖率体验改进”,然后重启 Visual Studio 来启用更快的代码覆盖率测试结果。

按块或行报告

代码覆盖率将以块为单位计数。 块是恰好有一个入口点和出口点的一段代码。 在测试运行期间,如果程序的控制流通过某个块,则将该块计为“已覆盖”。 块的使用次数对结果没有影响。

还可以通过在表标题中选择“添加/移除列”来按行显示结果。 某些用户更喜欢行计数,因为百分比与你在源代码中看到的段的大小更为对应。 一个很长的计算块即使占用多行,也将计为一行。

提示

一个代码行可包含多个代码块。 如果是这种情况,并且测试运行执行行中的所有代码块,则将该代码行计为一行。 如果执行行中的某些代码块(但不是所有代码块),则将其计算为部分行。

筛选代码覆盖率结果

“代码覆盖率结果”窗口通常显示整个解决方案的结果。 可以筛选结果,以仅显示当前分支中已更新的文件的结果。

  • 若要查看变更集报表,请在“代码覆盖率结果”窗口中选择“配置代码覆盖率视图”图标。 然后从“报表内容”下拉列表中选择“变更集报表”。 更新活动存储库和基本分支,以便与之进行比较,从而提供比较报告。

在“代码覆盖率结果”窗口的搜索框中,可以通过几种方式来筛选报表。

  • 若要“按名称搜索”(在窗口中仅显示与搜索字符串匹配的项),请在搜索框中输入搜索字符串。
  • 若要“按类型筛选”,请在搜索框中输入类型的名称。
  • 若要“显示全部”,请清除搜索框。
  • 若要“显示 100% 完全覆盖”,请在搜索框中输入“已覆盖(行百分比)”:“100”。
  • 若要“显示(>0% && < 100% )部分覆盖,请输入“部分覆盖(行百分比)”:“<##”,其中将 ## 替换为覆盖的百分比。
  • 若要“显示 0% 覆盖”,请在搜索框中输入“未覆盖(行百分比)”:“0”。

管理代码覆盖率结果

“代码覆盖率结果”窗口通常显示最新运行的结果。 如果更改了测试数据或每次只运行一部分测试,结果将会变化。

“代码覆盖率结果”窗口也可用来查看以前的结果或在其他计算机上获取的结果。

你可以合并多个运行的结果,例如来自使用不同的测试数据的运行的结果。

  • 若要查看以前的结果集,请从下拉菜单中选择它。 该菜单将会显示一个临时列表。打开新的解决方案时,将会清除该列表。

  • 要查看以前会话中的结果,请选择“导入代码覆盖率结果”,导航到解决方案中的 TestResults 文件夹,然后导入 .coverage 文件 。

    如果源代码自 .coverage 文件生成之后已发生更改,则覆盖率着色可能不正确。

  • 若要使结果可作为文本读取,请选择“导出代码覆盖率结果”。 这将生成可使用其他工具处理或在邮件中轻松发送的可读 .coveragexml 文件。 还可以选择导出格式,例如 Cobertura。

  • 要将结果发送给其他人,请发送 .coverage 文件或导出的 .coveragexml 文件 。 他们随后可以导入该文件。 如果他们具有相同版本的源代码,还可以看到覆盖率着色。

合并不同运行的结果

在某些情况下,将根据测试数据来使用代码中的不同块。 因此,你可能需要组合来自不同的测试运行的结果。

例如,假设你在运行某个测试(输入为“2”)时发现某个特定函数已被覆盖了 50%。 当你第二次运行该测试(输入为“-2”)时,你在覆盖着色视图中发现该函数的另外 50% 也被覆盖。 现在,你合并来自这两个测试运行的结果,报告和覆盖率着色视图显示该函数已经 100% 被覆盖。

为此,请使用“代码覆盖率”窗口中的“合并”按钮图标。“合并代码覆盖率结果”。 你可以选择最近的运行或导入的结果的任意组合。 如果要组合导出的结果,则必须先将其导入。

使用“导出代码覆盖率结果”可保存合并操作的结果。

有关合并的限制

  • 如果你合并不同版本的代码中的覆盖率数据,结果将单独显示,但不会合并。 若要获取完全合并的结果,请使用相同的代码生成,并且仅更改测试数据。

  • 如果你合并一个先导出然后导入的结果文件,则只能按行查看结果,而不能按块查看结果。 使用“添加/移除列”命令可显示行数据。

  • 如果你合并来自 ASP.NET 项目的测试的结果,则将显示各个测试的结果,而不是合并的测试的结果。 此行为只适用于 ASP.NET 项目本身:任何其他程序集的结果都将合并。

从代码覆盖率结果中排除元素

例如,如果代码是从文本模板生成的,则你可能希望从覆盖率分数中排除代码中的特定元素。 将特性 System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute 添加到以下任一代码元素:类、结构、方法、属性、属性 setter 或 getter、事件。

提示

排除某个类并不会排除它的派生类。

例如:

using System.Diagnostics.CodeAnalysis;
...
public class ExampleClass1
{
    [ExcludeFromCodeCoverage]
    void ExampleMethod() {...}

    [ExcludeFromCodeCoverage] // exclude property
    int ExampleProperty1
    { get {...} set{...}}

    int ExampleProperty2
    {
        get
        {
            ...
        }
        [ExcludeFromCodeCoverage] // exclude setter
        set
        {
            ...
        }
    }

}
[ExcludeFromCodeCoverage]
class ExampleClass2 { ... }

使用以下宏:

ExcludeFromCodeCoverage(ExclusionName, L"FunctionName");

ExcludeSourceFromCodeCoverage(ExclusionName, L"SourceFilePath");

  • ExclusionName 是唯一名称。

  • FunctionName 是完全限定的函数名。 它可能包含通配符。 例如,若要排除某个类的所有函数,应编写 MyNamespace::MyClass::*

  • SourceFilePath 是 .cpp 文件的本地或 UNC 路径。 它可能包含通配符。 以下示例将排除特定目录中的所有文件:\\MyComputer\Source\UnitTests\*.cpp

  • #include <CodeCoverage\CodeCoverage.h>

  • 将对排除宏的调用放在全局命名空间中,而不是放在任何命名空间或类中。

  • 你可以将排除放在单元测试代码文件或应用程序代码文件中。

  • 必须通过设置编译器选项或使用 #pragma managed(off) 将排除编译为非托管(本机)代码。

注意

若要排除 C++/CLI 代码中的函数,应对函数应用特性 [System::Diagnostics::CodeAnalysis::ExcludeFromCodeCoverage]。 这与 C# 中的做法相同。

包括或排除其他元素

仅对已加载并且在 .dll 或 .exe 文件所在相同目录中有可用的 .pdb 文件的程序集执行代码覆盖率分析 。 因此,在某些情况下,可以通过获取适当的 .pdb 文件的副本来扩展包含的一组程序集。

可通过编写 .runsettings 文件来加强控制为代码覆盖率分析选择哪些程序集和元素。 例如,你可以排除特定类型的程序集,而不必向它们的类添加特性。 有关详细信息,请参阅自定义代码覆盖率分析

分析 Azure Pipelines 中的代码覆盖率

签入代码时,你的测试以及其他团队成员的测试将在生成服务器中运行。 这对分析 Azure Pipelines 中的代码覆盖率很有用,以提供整个项目中最新、最全面的覆盖率信息。 Azure Pipelines 中的代码覆盖率还包含用户不常在开发计算机上运行的自动系统测试和其他编码的测试。

从命令行分析代码覆盖率

若要从命令行运行测试,请使用 vstest.console.exe 实用工具。 代码覆盖率是由 /EnableCodeCoverage 选项调用的 vstest.console.exe 实用工具的一个选项。

  1. 启动“Visual Studio 开发人员命令提示”:

    在 Windows“开始”菜单中,搜索 Developer Command Prompt for VS 并选择与搜索文本相关联的应用结果。

  2. 在命令提示符处运行以下命令:

    vstest.console.exe MyTestAssembly.dll /EnableCodeCoverage
    

    提示

    对于 Developer PowerShell,shell 的起始目录是 Visual Studio Project Location。 将 MyTestAssembly.dll 替换为路径和测试文件名。 有关详细信息,请参阅 VSTest.Console.exe 命令行选项

疑难解答

如果看不到代码覆盖率结果,代码覆盖率疑难解答一文可能有所帮助。