如何配置runsettings文件仅检测被测项目,动态排除NuGet DLL适配TFS构建?
I’ve worked through exactly this scenario with TFS (now Azure DevOps Server) build pipelines—getting code coverage to only focus on our actual project code while ignoring all NuGet dependencies. Here’s a practical, actionable setup:
1. Base RunSettings Configuration to Target Your Project
First, we’ll define which assemblies to include in code coverage (your actual project) and exclude everything else by default. This ensures we only track coverage for the code you care about.
Create a .runsettings file with the following structure:
<?xml version="1.0" encoding="utf-8"?> <RunSettings> <DataCollectionRunSettings> <DataCollectors> <DataCollector friendlyName="Code Coverage" uri="datacollector://Microsoft/CodeCoverage/2.0" assemblyQualifiedName="Microsoft.VisualStudio.Coverage.DynamicCoverageDataCollector, Microsoft.VisualStudio.TraceCollector, Version=17.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <Configuration> <CodeCoverage> <!-- Include only your target project's assembly --> <Include> <ModulePaths> <Include>$(TargetDir)\YourProjectName.dll</Include> </ModulePaths> <Functions> <Include>YourProjectName.*</Include> </Functions> </Include> <!-- Exclude all other assemblies by default --> <Exclude> <ModulePaths> <Exclude>*</Exclude> </ModulePaths> </Exclude> <!-- Additional coverage settings --> <UseVerifiableInstrumentation>True</UseVerifiableInstrumentation> <AllowLowIntegrityProcesses>True</AllowLowIntegrityProcesses> <CollectFromChildProcesses>True</CollectFromChildProcesses> <CollectAspDotNet>False</CollectAspDotNet> </CodeCoverage> </Configuration> </DataCollector> </DataCollectors> </DataCollectionRunSettings> </RunSettings>
Replace YourProjectName with the name of your actual tested project assembly. The $(TargetDir) variable resolves to the build output directory, working seamlessly in both local development and TFS builds.
2. Exclude All NuGet DLLs
Even with base include/exclude rules, add explicit exclusions to ensure no NuGet-managed DLLs slip into coverage reports. NuGet assemblies typically live in the packages folder or have distinct namespace patterns. Add these rules inside the <Exclude> section of the <CodeCoverage> block:
<Exclude> <!-- Existing default exclude rule --> <ModulePaths> <Exclude>*</Exclude> <!-- Exclude all assemblies from NuGet packages folder --> <Exclude>**\packages\**\*.dll</Exclude> <!-- Optional: Exclude assemblies with "NuGet" in their name for edge cases --> <Exclude>*NuGet*.dll</Exclude> </ModulePaths> <!-- Exclude common NuGet package namespaces --> <Functions> <Exclude>NuGet.*</Exclude> <Exclude>Microsoft.*</Exclude> <Exclude>Newtonsoft.*</Exclude> <!-- Add other package namespaces your project uses --> </Functions> </Exclude>
Adjust the namespace exclusions to match the NuGet packages your project depends on. This ensures even if a NuGet DLL ends up in the target directory, its code won’t be counted in coverage.
3. Dynamic Configuration for TFS Build Definitions
To make this setup flexible for TFS builds, we can parameterize the runsettings file or generate it dynamically during the pipeline. Here are two reliable approaches:
Option A: Use TFS Build Variables
Edit your .runsettings file to use TFS build variables instead of hardcoded values:
<Include> <ModulePaths> <Include>$(Build.BinariesDirectory)\$(TargetAssemblyName).dll</Include> </ModulePaths> </Include>
Then, in your TFS build definition:
- Go to the Variables tab and add
TargetAssemblyNamewith your project assembly’s name. - In the Test step, specify the path to your
.runsettingsfile under Advanced > Run settings file.
Option B: Generate RunSettings Dynamically with PowerShell
For more flexibility (e.g., auto-detecting NuGet packages), add a PowerShell script step before your test step in the TFS pipeline. This script generates the .runsettings file on the fly:
$runSettingsContent = @" <?xml version="1.0" encoding="utf-8"?> <RunSettings> <DataCollectionRunSettings> <DataCollectors> <DataCollector friendlyName="Code Coverage" uri="datacollector://Microsoft/CodeCoverage/2.0" assemblyQualifiedName="Microsoft.VisualStudio.Coverage.DynamicCoverageDataCollector, Microsoft.VisualStudio.TraceCollector, Version=17.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <Configuration> <CodeCoverage> <Include> <ModulePaths> <Include>$(Build.BinariesDirectory)\$(TargetAssemblyName).dll</Include> </ModulePaths> </Include> <Exclude> <ModulePaths> <Exclude>*</Exclude> <Exclude>**\packages\**\*.dll</Exclude> </ModulePaths> </Exclude> </CodeCoverage> </Configuration> </DataCollector> </DataCollectors> </DataCollectionRunSettings> </RunSettings> "@ $runSettingsPath = Join-Path $(Build.ArtifactStagingDirectory) "Dynamic.runsettings" $runSettingsContent | Out-File $runSettingsPath -Encoding utf8 # Pass the generated path to the test step via a build variable Write-Host "##vso[task.setvariable variable=RunSettingsPath]$runSettingsPath"
Then, in your test step, set the runsettings file path to $(RunSettingsPath).
4. TFS Build Pipeline Final Setup
- Ensure your
.runsettingsfile (or the generation script) is checked into source control. - In the TFS build definition’s Test step:
- Under Code coverage, select Custom and specify the runsettings file path (or dynamic variable).
- Verify the build agent has permissions to read/write to the directory where the runsettings file is stored.
This setup ensures your code coverage reports only include your project’s code, exclude all NuGet dependencies, and work reliably in TFS builds.
内容的提问来源于stack exchange,提问作者Rasen244

