问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

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

创作时间:
作者:
@小白创作中心

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

引用
1
来源
1.
https://learn.microsoft.com/zh-cn/visualstudio/test/using-code-coverage-to-determine-how-much-code-is-being-tested?view=vs-2022

代码覆盖率是软件测试中的一个重要概念,它用于衡量源代码中被测试用例执行的部分所占的比例。通过分析代码覆盖率,开发人员可以了解哪些代码已经被测试,哪些代码尚未被测试,从而有针对性地编写更多的测试用例,提高软件质量。本文将详细介绍如何在Visual Studio中使用代码覆盖率功能。

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

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

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

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

要求

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

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

分析代码覆盖率

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


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

  1. 测试运行后,若要查看已运行的行,请选择
    “代码覆盖率结果”窗口中的“显示代码覆盖率着色”。 默认情况下,测试所涵盖的代码以浅蓝色突出显示。


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

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

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

  1. 如果结果显示覆盖率较低,请调查代码中哪些部分未被执行,并编写更多测试以便覆盖这些部分。 开发团队通常以大约 80% 的代码覆盖率为目标。 在某些情况下,可以接受较低的覆盖范围。 例如,从标准模板生成某些代码时,可以接受较低的覆盖率。

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

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

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

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

提示
从 Visual Studio 2022 版本 17.2 开始,可以选择工具 > 选项 > 环境 > 预览功能启用最新的代码覆盖率功能,然后选择代码覆盖率体验改进,然后重启 Visual Studio。

按块或行报告

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

还可以通过在表标题中选择添加/删除列来显示行的结果。 某些用户更喜欢行数,因为百分比更接近于源代码中看到的片段的大小。 一个长的计算区块将算作一个单独的块,即使它占用了许多行。

提示
一行代码可以包含多个代码块。 如果是这种情况,并且测试运行覆盖了该行内的所有代码块,则算作一行。 如果一行中的部分代码块被执行,但不是全部被执行,则将其计为部分行。

代码覆盖率结果视图

代码覆盖率结果窗口通常按照项目/类/方法的层次结构来组织报表。 可以更改此项以显示目录/文件/方法级别的覆盖范围。

  • 要查看源报表,请在代码覆盖率结果窗口中选择配置代码覆盖率视图图标。 然后从报表样式下拉列表中选择源视图

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

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

代码覆盖率结果窗口中的搜索框中,可以通过多种不同的方式对报告进行筛选。

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

管理代码覆盖率结果

“代码覆盖率结果”窗口通常显示最新运行的结果。 如果更改测试数据,或者每次只运行一些测试,结果将有所不同。

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

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

  • 若要查看上一组结果,请从下拉菜单中选择它。 菜单中显示的是一个临时列表,每当打开新解决方案时该列表就会被清空。
  • 若要查看上一个会话的结果,请选择导入结果,导航到解决方案中的TestResults文件夹,然后导入.coverage文件。

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

  • 若要使结果可作为文本读取,请选择“导出结果”,选择 .xml 作为“另存为类型”。 这将生成可读.xml文件,你可以使用其他工具进行处理或轻松地在邮件中发送。 还可以选择导出格式,例如 Cobertura。
  • 若要将结果发送到其他人,请发送.coverage文件或导出的.xml文件。 然后,他们可以导入文件。 如果他们具有相同版本的源代码,还可以看到覆盖率着色。

合并不同运行的结果

在某些情况下,代码中的不同块会根据测试数据而使用。 因此,你可能希望合并来自不同测试运行的结果。

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

使用
“合并结果”来执行此操作。 你可以选择最近的运行或导入的结果的任意组合。 如果要合并导出的结果,必须先导入它们。

使用导出结果保存合并操作的结果。

合并的限制

  • 如果合并不同版本的代码的覆盖率数据,则结果会单独显示,但不会合并它们。 若要获取完全组合的结果,请使用相同的代码版本,仅更改测试数据。
  • 如果合并导出并导入的结果文件,则只能按行查看结果,而不能按块查看结果。 使用添加/删除列命令显示行数据。
  • 如果合并 ASP.NET 项目测试的结果,个别测试的结果会显示出来,但不会合并。 此行为仅适用于 ASP.NET 工件本身:将汇总任何其他程序集的结果。

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

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

提示
排除类不会排除其派生类。

例如:

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 { ... }
Imports System.Diagnostics.CodeAnalysis
Class ExampleClass1
    <ExcludeFromCodeCoverage()>
    Public Sub ExampleSub1()
        ...
    End Sub
    ' Exclude property
    < ExcludeFromCodeCoverage()>
    Property ExampleProperty1 As Integer
        ...
    End Property
    ' Exclude setter
    Property ExampleProperty2 As Integer
        Get
            ...
        End Get
     <ExcludeFromCodeCoverage()>
        Set(ByVal value As Integer)
            ...
        End Set
    End Property
End Class
<ExcludeFromCodeCoverage()>
Class ExampleClass2
...
End Class
// A .cpp file compiled as managed (CLI) code.
using namespace System::Diagnostics::CodeAnalysis;
...
public ref class ExampleClass1
{
  public:
    [ExcludeFromCodeCoverage]
    void ExampleFunction1() { ... }
    [ExcludeFromCodeCoverage]
    property int ExampleProperty2 {...}
    property int ExampleProperty2 {
      int get() { ... }
     [ExcludeFromCodeCoverage]
      void set(int value) { ...  }
   }
}
[ExcludeFromCodeCoverage]
public ref class ExampleClass2
{ ... }

排除本机C++代码中的元素

若要排除 C++ 代码中的非托管(本机)元素:

#include <CodeCoverage\CodeCoverage.h>
...
// Exclusions must be compiled as unmanaged (native):
#pragma managed(push, off)
// Exclude a particular function:
ExcludeFromCodeCoverage(Exclusion1, L"MyNamespace::MyClass::MyFunction");
// Exclude all the functions in a particular class:
ExcludeFromCodeCoverage(Exclusion2, L"MyNamespace::MyClass2::*");
// Exclude all the functions generated from a particular template:
ExcludeFromCodeCoverage(Exclusion3, L"*::MyFunction<*>");
// Exclude all the code from a particular .cpp file:
ExcludeSourceFromCodeCoverage(Exclusion4, L"*\\unittest1.cpp");
// After setting exclusions, restore the previous managed/unmanaged state:
#pragma managed(pop)

使用以下宏:
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# 相同。

包括或排除其他元素

代码覆盖率分析仅在加载的程序集上执行,.pdb文件在与.dll或.exe文件相同的目录中可用。 因此,在某些情况下,可以通过获取适当的 .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

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

故障排除

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

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号