.NET Core 中的代码覆盖率终于变得简单了






4.95/5 (9投票s)
.NET Core 中的代码覆盖率终于变得简单了
几个月前,在 ASP.NET Core 中在命令行计算代码覆盖率相当困难。幸运的是,从上个月开始,随着 Visual Studio 15.8 的发布,生成该指标变得很容易。
起初,这是一个关于我最近基于微软新的、现代的、跨平台技术栈启动一个新项目时遇到的痛苦的故事。我本来打算详细说明我为了计算一个看似相当基础的指标而经历的许多步骤。
但取而代之的是,我将告诉你们,你们的生活可以变得多么幸福。
背景故事
我新项目使用的技术栈是这样的
- ASP.NET Core
- XUnit
- Azure DevOps (VSTS)
- Cake
等等,在我将我的读者数量减少到零之前,让我稍微回顾一下,请耐心点。
如果你们读了我上一篇关于从团队角度来看计算代码覆盖率重要性的博文,你们就知道什么是代码覆盖率以及为什么我如此重视它。而且,如果你们读过我关于为什么 Cake 是一个如此出色的自动化 DevOps 管道工具的过往文章(或视频),那么你们就知道我打算如何解决 DevOps 问题。如果没读过,让我来简要总结一下选择 Cake 的原因。
- 供应商中立(可以轻松切换到 Jenkins 或 Team City)
- 支持任务依赖管理
- 可在本地运行
- 易于调试
- 版本控制
- C#
够了。其余的技术都是项目需求,XUnit 除外,它随ASP.NET Boilerplate 一起提供(更多内容将在未来的文章中讨论),我也不在乎去更改它。如果你是 NUnit 用户,只需将本文中其余地方的“X
”替换为“N
”,结果是一样的。
使用 ASP.NET Core 进行测试
我将接续这个叙述,在安装了 Cake 并编写了类似这样的构建任务脚本之后。
Task("Build")
.IsDependentOn("Restore")
.Does(() =>
{
var settings = new DotNetCoreBuildSettings {
Configuration = configuration
};
DotNetCoreBuild("./CakeCoverageTest.sln", settings);
});
这时,我非常高兴地发现,由于测试是一等公民,我可以这样进行测试。
Task("Test")
.Description("Runs unit tests.")
.IsDependentOn("Build")
.Does(() =>
{
var testLocation = File("./CakeCoverageTest.Test/CakeCoverageTest.Test.csproj");
var settings = new DotNetCoreTestSettings {
NoBuild = true
};
DotNetCoreTest(testLocation, settings);
});
这相当于
dotnet.exe test "CakeCoverageTest.Test/CakeCoverageTest.Test.csproj" --no-build
它运行 ASP.NET Core 的内置测试基础设施,该基础设施原生支持 XUnit 和 NUnit。
NoBuild = true
是因为否则 .NET test 命令会尝试构建,而我喜欢让 Cake 来处理我的依赖项。这可以避免重复构建,例如,如果一个高级的Deploy任务同时依赖于Test和Package,而它们又都依赖于Build。
在这种情况下,Cake 会智能地只构建一次,如果我运行Deploy。这与 Make、Psake、Rake 或 MS Build 等任何“AKE”工具没有什么真正不同,但与 bash 或 PowerShell 脚本相比,它有一个好处,即你无需使用全局状态。任务依赖管理++。
获取覆盖率
在 Visual Studio 15.8 之前,获取覆盖率需要切换到仅限 Windows 的 vstest.console.exe 替代方案,并且需要 Visual Studio Enterprise。然后,需要添加一个测试适配器,修复该工具路径的一个 bug,添加对 Microsoft.CodeCoverage
NuGet 包的引用,在主 .csproj 文件中添加一行 <debugtype>Full
,并解释新旧 pdb(程序数据库)调试信息文件。
幸运的是,从九月份开始,.NET test 有了一个新参数:--collect "Code Coverage"。不幸的是,它仍然仅限 Windows,但他们已经取消了对 Visual Studio Enterprise 的要求。使其跨平台已在计划中,甚至可能在你阅读本文时就已经支持。
Cake 尚未支持覆盖率参数,但通过 ArgumentCustomization
参数的灵活性,有一个简单的变通方法。
Task("Test")
.Description("Runs unit tests.")
.IsDependentOn("Build")
.Does(() =>
{
var testLocation = File("./CakeCoverageTest.Test/CakeCoverageTest.Test.csproj");
var settings = new DotNetCoreTestSettings {
Configuration = configuration,
NoBuild = true,
ArgumentCustomization = args => args
.Append("--collect").AppendQuoted("Code Coverage")
.Append("--logger").Append("trx")
};
DotNetCoreTest(testLocation, settings);
});
这相当于
dotnet test "CakeCoverageTest.Test/CakeCoverageTest.Test.csproj"
--configuration Release --no-build --collect "Code Coverage" --logger trx
如果运气好的话,它应该会输出类似这样的内容。
Starting test execution, please wait...
Results File:
C:\dev\Cake\CakeCoverageTest\CakeCoverageTest.Test\TestResults\Lee_LEE-XPS_2018-10-21_17_34_47.trx
Attachments:
C:\dev\Cake\CakeCoverageTest\CakeCoverageTest.Test\TestResults\
3ba423f8-2f10-4bc2-8b53-b4fef907369e\Lee_LEE-XPS_2018-10-21.17_34_44.coverage
Total tests: 1. Passed: 1. Failed: 0. Skipped: 0.
Test Run Successful.
这太棒了,不是吗?!我们基本上完成了。
发布覆盖率
要在 Visual Studio 中查看覆盖率数据,我们仍然需要 Enterprise 版本。但无论如何,我们可以使用 Azure DevOps 生成定义任务来获取并发布文件。首先,生成任务。
市场上有 Cake 任务,但上面内置的 Powershell 任务也很好用。
然后,我们只需要发布测试结果。
如果我们运行这个命令,我们应该会得到这个。
看看那一行“Code coverage succeeded
”以及开头的“50.00% lines covered
”行!简直丝滑。
摘要
我最初是想讲述一个充满悲伤、痛苦和咬牙切齿的故事。但相反,我很高兴地告诉大家,我们现在生活在一个多么美好的世界。在 ASP.NET Core 中计算代码覆盖率现在变得很容易了。干得好,微软!干得好!