dotCover
dotCover 运行程序使用 JetBrains dotCover 生成 .NET 进程的覆盖率报告。 生成的报告将发布到构建结果页面的 Code Coverage tab。
这个运行器也可以放在多个前置 .NET 步骤后,以合并它们各自的代码覆盖率并发布综合报告。
这一部分解释了如何使用 runner 设置。 请参考以下部分的示例,了解如何根据您当前的任务组合这些设置。

dotCover 工具 — 选择预安装版本或 自定义 版本的 dotCover。
可执行文件 和 命令行实参 — 可选设置,允许您在 dotCover 覆盖率配置文件下运行具有所需参数的自定义进程。 可执行文件 字段接受生成配置文件进程的对象路径(例如,.NET CLI 或 dotCover 工具本身的 .exe/.dll)。 如果您使用此步骤合并由之前的 dotCover、 .NET 或 NUnit 运行程序生成的快照,请将这些设置留空。
生成覆盖率报告 — 指定生成的代码覆盖率报告是否应在其 代码覆盖率 选项卡上显示数据。
如果您不需要在构建结果页上发布报告,请不要勾选此设置。 例如,如果您打算发布生成的 .html 和 .dcvr 文件 作为构建成品 并在其他地方使用它们。
将额外的 dotCover 快照包含到报告中 — 运行程序应使用的 .dcvr 快照路径,以生成最终的覆盖率报告。
请注意,由于 dotCover 会自动从前面的 dotCover 和 .NET 步骤中收集快照,只要所有需要的快照都在同一配置中生成,您就无需定义这些规则。 这个设置允许您包含通过 artifact dependencies 导入的独立配置中的快照。
程序集筛选器 — 输入 "+:assemblyName" 以包含程序集,或输入 "-:assemblyName" 以从代码覆盖率中排除程序集。
特性筛选器 — 输入 "-:attributeName" 以从代码覆盖率中排除标记有此属性的任何代码。
其他实参 —
dotCover 覆盖率
命令的其他命令行参数列表。
dotCover 运行程序可用作一站式工具,测试所需项目并生成代码覆盖率报告。 以下的 Kotlin DSL 样本阐述了这一设置。
// Launching .NET to test a project and generate a report
object MyConfig : BuildType({
steps {
dotCover {
name = "dotCover step with .Net test"
id = "dotcover"
toolPath = "%teamcity.tool.JetBrains.dotCover.CommandLineTools.DEFAULT%"
executable = "%DotNetCLI_Path%"
commandLineArguments = """test %teamcity.build.checkoutDir%\ProjectA\proj_A.csproj"""
}
}
})
// Launching .NET to test a project and generate a report
object MyConfig : BuildType({
steps {
dotCover {
id = "dotcover"
toolPath = "%teamcity.tool.JetBrains.dotCover.CommandLineTools.DEFAULT%"
executable = "%teamcity.tool.JetBrains.dotCover.CommandLineTools.DEFAULT%/dotCover.dll"
commandLineArguments = "dotnet --targetWorkingDir=%teamcity.build.checkoutDir% -- test ./ProjectA/proj_A.csproj"
}
}
})
然而,在这个简单的场景中,最终结果类似于在其设置中启用 dotNet 覆盖率的运行 .NET 步骤。 dotCover 运行程序的真正优势在于其能够从不同来源收集快照并生成合并的代码覆盖率报告。 以下示例说明了如何根据这些快照的确切来源设置 dotCover 运行器。
下面的示例配置包含多个 .NET 步骤,用以测试不同的项目。 这些步骤中的每一个都在 Code Coverage(代码覆盖率) 下选择了 "JetBrains dotCover"。 最终的 dotCover 步骤不会生成其自己的快照。 相反,它收集所有 .NET 运行器的快照,以创建最终的综合报告,并发布到 代码覆盖率标签页。
此设置仅需要选择 生成覆盖率报告 选项,其他运行程序设置保持为空。
import jetbrains.buildServer.configs.kotlin.*
import jetbrains.buildServer.configs.kotlin.buildSteps.dotCover
object ConsolidatedReport : BuildType({
id("consolidatedreport")
name = "Code coverate report merged from three .NET steps"
steps {
dotnetTest {
id = "dotnet"
projects = "projectA/proj_A.csproj"
sdk = "6"
coverage = dotcover {
toolPath = "%teamcity.tool.JetBrains.dotCover.CommandLineTools.DEFAULT%"
}
}
dotnetTest {
id = "dotnet_1"
projects = "projectB/proj_B.csproj"
sdk = "6"
coverage = dotcover {
toolPath = "%teamcity.tool.JetBrains.dotCover.CommandLineTools.DEFAULT%"
}
}
// More .NET runners that test separate projects and generate dotCover snapshots
dotCover {
id = "dotcover"
toolPath = "%teamcity.tool.JetBrains.dotCover.CommandLineTools.DEFAULT%"
}
}
})
下面的 构建链 包含两个配置。
配置 A 运行 .NET 步骤来测试带有代码覆盖率的单个项目。 生成的 .dcvr 快照被发布为工件。
import jetbrains.buildServer.configs.kotlin.*
import jetbrains.buildServer.configs.kotlin.buildSteps.dotCover
object ConfigA : BuildType({
name = "Configuration A: Test with code coverage and publish snapshots"
// Publish snaphots
// Note that the path to the snapshot directory may vary depending on the runner type and/or settings
// For example, for NUnit runner use "%teamcity.agent.work.dir%\..\temp\agentTmp\dotNetCoverageResults\*.dcvr" instead
artifactRules = """%teamcity.agent.work.dir%\..\temp\agentTmp\*.dcvr"""
steps {
dotnetTest {
id = "dotnet"
projects = "projectA/proj_A.csproj"
sdk = "6"
coverage = dotcover {
toolPath = "%teamcity.tool.JetBrains.dotCover.CommandLineTools.DEFAULT%"
}
}
dotnetTest {
id = "dotnet_1"
projects = "projectB/proj_B.csproj"
sdk = "6"
coverage = dotcover {
toolPath = "%teamcity.tool.JetBrains.dotCover.CommandLineTools.DEFAULT%"
}
}
// ...
// More .NET runners that test separate projects and generate dotCover snapshots
}
})
配置 B 的最终 dotCover 步骤通过合并以下快照创建联合报告:
由 Configuration B 的 .NET 步骤生成的快照(测试 "Project C")
dotCover 自己从测试 "Project D" 中生成的快照
由配置A生成并通过 artifact dependencies导入到配置B的快照
import jetbrains.buildServer.configs.kotlin.*
import jetbrains.buildServer.configs.kotlin.buildSteps.dotCover
object ConfigB : BuildType({
name = "Configuration B: Test with code coverage, import snapshots, and publish report"
steps {
dotnetTest {
id = "dotnet"
projects = "projectC/proj_C.csproj"
sdk = "6"
coverage = dotcover {
toolPath = "%teamcity.tool.JetBrains.dotCover.CommandLineTools.DEFAULT%"
}
}
dotCover {
id = "dotcover"
toolPath = "%teamcity.tool.JetBrains.dotCover.CommandLineTools.DEFAULT%"
executable = "%DotNetCLI_Path%"
commandLineArguments = "test ./ProjectD"
snapshotPaths = "%teamcity.build.workingDir%/*.dcvr"
}
}
dependencies {
artifacts(Build) {
buildRule = lastSuccessful()
cleanDestination = true
artifactRules = "+:*.dcvr"
}
}
})
您的 .NET 运行器可以利用 并行测试 构建功能,将庞大的测试套件分解成在不同代理上执行的单独批次。 如果您将 dotCover 步骤添加到具有并行测试的配置中,它将不会合并由单独构建生成的快照,这些构建运行独立的批次。 每个单独的构建将在构建结果页面的 概述 选项卡上显示其自己的结果,而带有合并报告的 Code Coverage(代码覆盖率) 选项卡将不存在。

如果您想要一个综合报告,您可以采用类似于 来自构建链 部分所示的解决方案:创建一个依赖的构建配置,它将从所有批次收集快照,并将它们合并到一个单一的报告中。
在这个使用场景中的区别是,您应在将快照发布为工件之前重命名它们。 否则,由于每个并行构建具有相同的设置,快照有相同的名称,每个在更快的并行构建后完成的构建都会覆盖其制品。 参考以下部分以了解更多信息: 发布批量构建产生的工件
// Primary build configuration
// Performs actual tests and generates coverage snapshots
object PrimaryConfig : BuildType({
id = AbsoluteId("ConfigA")
name = "Build"
// use build.parallelTests parameter to generate unique artifact names
artifactRules = """%teamcity.agent.work.dir%\..\temp\agentTmp\*.dcvr => Snapshot_%teamcity.build.parallelTests.currentBatch%"""
steps {
dotnetTest {
id = "dotnet_1"
projects = "ProjectA/proj_A.csproj"
sdk = "6"
coverage = dotcover {
toolPath = "%teamcity.tool.JetBrains.dotCover.CommandLineTools.DEFAULT%"
}
}
// .NET runners that test separate projects and generate dotCover snapshots
}
features {
parallelTests {
numberOfBatches = 2
}
}
})
// Dependent build configuration
// Retrieves snapshots from parallel builds and produces a consolidated report
object DotCoverReportConfig : BuildType({
id = AbsoluteId("ConfigB")
name = "dotCover Report"
steps {
dotCover {
id = "dotcover"
toolPath = "%teamcity.tool.JetBrains.dotCover.CommandLineTools.DEFAULT%"
snapshotPaths = "%teamcity.build.workingDir%/*/*.dcvr"
}
}
dependencies {
artifacts(DotCoverRunner_ParallelTestsWithOneCommonCoverageReport_Build) {
buildRule = lastSuccessful()
cleanDestination = true
artifactRules = "+:*/*.dcvr"
}
}
})
Thanks for your feedback!