Handling .NET SDK Version Differences in `dotnet test` Argument Parsing
The dotnet test command adapts its CLI parsing rules based on the active .NET SDK version, requiring a -- separator for Microsoft Testing Platform arguments in SDK 8 and 9 while accepting them as first-class options in SDK 10 and later.
The dotnet/skills repository provides detailed guidance on handling .NET SDK version differences in dotnet test argument parsing to ensure reliable test execution across different SDK generations. Understanding these parsing rules is essential when working with the Microsoft Testing Platform (MTP) or legacy VSTest runners, as incorrect argument placement can lead to silent failures or empty test runs.
SDK Version Detection Strategy
The platform-detection skill determines the active SDK version by executing dotnet --version, which respects any global.json file present in the repository. According to plugins/dotnet-test/skills/platform-detection/SKILL.md, this version check is the foundation for the run-tests skill's conditional parsing logic.
The detected version drives whether the skill injects the -- separator when constructing command strings for MTP-based test runs.
Argument Parsing Rules by SDK Version
The dotnet test CLI implements different parsing strategies depending on the SDK generation. The run-tests skill documentation in plugins/dotnet-test/skills/run-tests/SKILL.md (lines 55-71) defines these boundaries:
SDK 8 and 9: Separator Required
For .NET SDK versions 8 and 9, MTP arguments must follow a -- separator. The separator demarcates where built-in dotnet test options end and platform-specific arguments begin.
dotnet test --project tests/MyApp.Tests.csproj -- --report-trx
In this example, --project is a built-in driver option parsed before the separator, while --report-trx is an MTP-specific argument passed after the separator.
SDK 10 and Later: Direct Argument Parsing
Starting with .NET SDK 10, MTP arguments are treated as first-class options. The double-dash separator is not required when passing platform-specific flags.
dotnet test --project tests/MyApp.Tests.csproj --report-trx
Built-in Flag Placement Rules
Regardless of SDK version, built-in dotnet test flags (e.g., --framework, --no-build, --configuration) must always precede the -- separator when one is used. This rule applies universally across all SDK versions documented in the run-tests skill.
Platform-Specific Syntax: VSTest vs. MTP
The argument parsing behavior differs significantly between the classic VSTest runner and the modern Microsoft Testing Platform.
VSTest Classic Behavior
VSTest arguments are passed directly to the underlying vstest.console and do not require the -- separator, regardless of SDK version. The syntax remains consistent across all supported SDKs:
dotnet test tests/LegacyTests.csproj --filter "TestCategory=Integration"
Microsoft Testing Platform Behavior
MTP (used by xUnit v3, MSTest, and TUnit) requires SDK-aware parsing:
-
SDK 8/9: Prefix MTP arguments with
--dotnet test -- --filter-trait "Category=Integration" -
SDK 10+: Pass arguments directly
dotnet test --project Tests/MyTests.csproj --filter-trait "Category=Integration"
The run-tests skill documentation (lines 240-246 in plugins/dotnet-test/skills/run-tests/SKILL.md) also notes that filter syntax varies by platform, such as using --filter-query for xUnit v3 specific queries.
Practical Code Examples
Running MTP Tests on SDK 9 (Requires Separator)
dotnet test --project tests/MyApp.Tests.csproj -- --report-trx
--projectis a built-indotnet testoption placed before----report-trxis an MTP argument placed after the separator
Running MTP Tests on SDK 10+ (No Separator)
dotnet test --project tests/MyApp.Tests.csproj --report-trx
All arguments are parsed at the top level by the SDK 10+ driver.
Using Filter Queries with xUnit v3 on SDK 10+
dotnet test --project tests/XUnitV3Tests.csproj --filter-query "/*/*/*IntegrationTests*/*[Category=Smoke]"
VSTest Syntax (Consistent Across SDKs)
dotnet test tests/LegacyTests.csproj --filter "TestCategory=Integration"
Why SDK-Aware Parsing Matters
Correct test discovery: Using the wrong separator causes MTP arguments to be ignored by the driver, resulting in empty test runs or failures to locate specific tests.
Consistent CI behavior: Automated pipelines must apply the same parsing rules as local development environments. Mismatched SDK versions between CI agents and developer machines produce divergent outcomes unless the execution logic adapts dynamically.
Future-proofing: As documented in plugins/dotnet-test/skills/coverage-analysis/SKILL.md, the same SDK version checks influence coverage-related arguments (e.g., --coverage placement). The skill automatically switches parsing modes, ensuring scripts remain portable across SDK upgrades without manual intervention.
Summary
- Always detect the SDK version using
dotnet --version(respectingglobal.json) before constructing commands. - Insert
--only for SDK 8/9 when passing MTP-specific flags; omit it for SDK 10+. - Place built-in options before the separator on all SDK versions where a separator is used.
- VSTest arguments require no separator regardless of SDK version.
Frequently Asked Questions
What is the purpose of the -- separator in dotnet test?
The -- separator demarcates the boundary between built-in dotnet test driver options and Microsoft Testing Platform-specific arguments. In SDK 8 and 9, arguments placed after -- are passed directly to the test platform rather than being parsed by the dotnet test CLI driver. SDK 10+ treats MTP arguments as first-class options, making the separator optional.
How do I determine which parsing rules apply to my environment?
Execute dotnet --version in your repository root to identify the active SDK version, as implemented in plugins/dotnet-test/skills/platform-detection/SKILL.md. If the output shows 8.x or 9.x, you must use the -- separator for MTP arguments. If the output shows 10.x or higher, you can pass MTP arguments directly without the separator.
Why do my MTP arguments work locally but fail in CI?
This typically occurs when the local environment runs .NET SDK 10+ while the CI pipeline uses SDK 8 or 9. The run-tests skill automatically detects this version mismatch, but manual scripts must account for the difference. Always verify CI agent SDK versions or use the version-agnostic patterns documented in plugins/dotnet-test/skills/run-tests/SKILL.md.
Are VSTest-specific arguments affected by SDK version changes?
No. VSTest arguments are passed directly to the underlying vstest.console executable and do not require the -- separator, regardless of whether you are using SDK 8, 9, or 10+. However, MTP-specific arguments (such as --report-trx or --filter-trait) must follow the SDK-dependent parsing rules outlined in the run-tests skill documentation.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →