After upgrading from .NET 9 SDK to .NET 10 SDK, TRX files no longer contain trait-based elements such as <Owners>, <TestCategory>, or custom <Properties>. This breaks tooling that relies on trait information from TRX files.
The root cause appears to be that TestCase.Traits returns an empty collection in .NET 10 SDK, so traits are not written to the TRX file.
Potential Root Cause
This regression may have been introduced by commit 2e77a1e ("Avoid iterator in TraitCollection.GetTraits") which was included in VSTest v18.0.0 and v18.0.1.
The commit changed TraitCollection.GetTraits() from using yield return to returning an array directly. This change may have inadvertently broken trait propagation to test adapters.
Environment
- Working: .NET SDK 9.0.309
- Broken: .NET SDK 10.0.102
- OS: Windows 11 / Linux (Ubuntu)
- Test Framework: xUnit 2.9.3 with xunit.runner.visualstudio 2.8.2
Repro Steps
1. Create the test project (TrxOwnerRepro.csproj):
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
</ItemGroup>
</Project>
2. Create the test class (SampleTests.cs):
using Xunit;
namespace TrxOwnerRepro;
public class SimpleTests
{
[Fact]
[Trait("Owner", "Billing")]
public void Test_WithOwnerTrait()
{
Assert.True(true);
}
}
3. Script to test with .NET 9 SDK (test-sdk9.ps1):
# Pin to .NET 9 SDK
@{ sdk = @{ version = "9.0.309" } } | ConvertTo-Json | Set-Content global.json
Write-Host "=== Testing with .NET 9 SDK ===" -ForegroundColor Cyan
Write-Host "SDK version: $(dotnet --version)"
# Clean and run tests
if (Test-Path TestResults) { Remove-Item -Recurse -Force TestResults }
dotnet test --logger "trx;LogFileName=results-sdk9.trx" --no-build 2>$null
dotnet build -c Debug 2>$null | Out-Null
dotnet test --logger "trx;LogFileName=results-sdk9.trx"
Write-Host "`n=== Checking TRX for traits ===" -ForegroundColor Cyan
$match = Select-String -Path "TestResults/results-sdk9.trx" -Pattern "<Owners>" -SimpleMatch
if ($match) {
Write-Host "SUCCESS: Traits found in TRX" -ForegroundColor Green
} else {
Write-Host "FAILURE: Traits NOT found" -ForegroundColor Red
}
4. Script to test with .NET 10 SDK (test-sdk10.ps1):
# Pin to .NET 10 SDK
@{ sdk = @{ version = "10.0.102" } } | ConvertTo-Json | Set-Content global.json
Write-Host "=== Testing with .NET 10 SDK ===" -ForegroundColor Cyan
Write-Host "SDK version: $(dotnet --version)"
# Clean and run tests
if (Test-Path TestResults) { Remove-Item -Recurse -Force TestResults }
dotnet build -c Debug 2>$null | Out-Null
dotnet test --logger "trx;LogFileName=results-sdk10.trx"
Write-Host "`n=== Checking TRX for traits ===" -ForegroundColor Cyan
$match = Select-String -Path "TestResults/results-sdk10.trx" -Pattern "<Owners>" -SimpleMatch
if ($match) {
Write-Host "SUCCESS: Traits found in TRX" -ForegroundColor Green
} else {
Write-Host "FAILURE: Traits NOT found (this is the regression)" -ForegroundColor Red
}
5. Run the scripts:
# Test with .NET 9 SDK
.\test-sdk9.ps1
# Expected: SUCCESS: Traits found in TRX
# Test with .NET 10 SDK
.\test-sdk10.ps1
# Expected: FAILURE: Traits NOT found (this is the regression)
Expected Behavior
TRX file should contain trait-based elements:
<UnitTest name="TrxOwnerRepro.SimpleTests.Test_WithOwnerTrait" ...>
<Execution id="..." />
<TestMethod ... />
<Owners>
<Owner name="Billing" />
</Owners>
</UnitTest>
Actual Behavior
TRX file is missing all trait-based elements:
<UnitTest name="TrxOwnerRepro.SimpleTests.Test_WithOwnerTrait" ...>
<Execution id="..." />
<TestMethod ... />
<!-- No <Owners> element -->
</UnitTest>
Impact
- Azure DevOps:
PublishTestResults@2 task uses traits for test result routing (see field mapping docs)
- Test filtering: Systems that filter or categorize tests based on traits are broken
- Bug triage automation: Systems that route test failures based on traits fail
- Third-party tooling: Any tool that parses TRX files for trait information fails
Related Issues
Suspected Commit
Commit: 2e77a1e
PR: #15249 - "Avoid iterator in TraitCollection.GetTraits"
The change modified TraitCollection.GetTraits() from using yield return to returning a pre-allocated array. This may have broken trait propagation.
After upgrading from .NET 9 SDK to .NET 10 SDK, TRX files no longer contain trait-based elements such as
<Owners>,<TestCategory>, or custom<Properties>. This breaks tooling that relies on trait information from TRX files.The root cause appears to be that
TestCase.Traitsreturns an empty collection in .NET 10 SDK, so traits are not written to the TRX file.Potential Root Cause
This regression may have been introduced by commit 2e77a1e ("Avoid iterator in TraitCollection.GetTraits") which was included in VSTest v18.0.0 and v18.0.1.
The commit changed
TraitCollection.GetTraits()from usingyield returnto returning an array directly. This change may have inadvertently broken trait propagation to test adapters.Environment
Repro Steps
1. Create the test project (
TrxOwnerRepro.csproj):2. Create the test class (
SampleTests.cs):3. Script to test with .NET 9 SDK (
test-sdk9.ps1):4. Script to test with .NET 10 SDK (
test-sdk10.ps1):5. Run the scripts:
Expected Behavior
TRX file should contain trait-based elements:
Actual Behavior
TRX file is missing all trait-based elements:
Impact
PublishTestResults@2task uses traits for test result routing (see field mapping docs)Related Issues
Suspected Commit
Commit: 2e77a1e
PR: #15249 - "Avoid iterator in TraitCollection.GetTraits"
The change modified
TraitCollection.GetTraits()from usingyield returnto returning a pre-allocated array. This may have broken trait propagation.