Use the open-source free `coverlet` toolchain for .NET code coverage.
Run .NET Tests
Run, filter, or troubleshoot .NET tests with `dotnet test`. USE FOR: running all tests in a project or solution; running only a subset (a specific test class, category, or trait) via filters; running a single target framework in a multi-TFM project (`--framework`); producing TRX reports; collecting crash or hang dumps; diagnosing why `dotnet test` fails or uses the wrong argument syntax. Detects the test platform (VSTest vs Microsoft.Testing.Platform) and framework (MSTest/xUnit/NUnit/TUnit), then picks the matching command: the `--` separator on .NET SDK 8/9 vs 10+, the right filter flag (--filter, --filter-class, --filter-trait, --filter-query, --treenode-filter), and TRX/blame flags. DO NOT USE FOR: writing test code (use code-testing-agent), iterating on failing tests without rebuilding (use mtp-hot-reload), CI/CD config, or debugging test logic.
Workflow
Quick Reference
| Platform | SDK | Command pattern | |----------|-----|----------------| | VSTest | Any | dotnet test [<path>] [--filter <expr>] [--logger trx] | | MTP | 8 or 9 | dotnet test [<path>] -- <MTP_ARGS> | | MTP | 10+ | dotnet test --project <path> <MTP_ARGS> |
Detection files to always check (in order): global.json -> .csproj -> Directory.Build.props -> Directory.Packages.props
If the prompt names a subset of tests (e.g., "integration tests", "smoke tests", a specific class, a specific TFM), plan to apply the matching filter / --framework in Step 3 — do not run the whole suite.
Step 1: Detect the test platform and framework
- Run
dotnet --versionin the project directory to determine the SDK version. This accounts forglobal.jsonSDK pinning. - Read
global.json— on .NET SDK 10+,"test": { "runner": "Microsoft.Testing.Platform" }is the authoritative MTP signal. If present, the project uses MTP and SDK 10+ syntax (no--separator). - Read
.csproj,Directory.Build.props, andDirectory.Packages.propsfor framework packages and MTP properties. Always check all three files — MTP properties are frequently set inDirectory.Build.propsrather than individual.csprojfiles. - For full detection logic (SDK 8/9 signals, framework identification), see the
platform-detectionskill.
What to look for in each file:
| File | Look for | Indicates | |------|----------|-----------| | global.json | "test": { "runner": "Microsoft.Testing.Platform" } | MTP on SDK 10+ | | global.json | "sdk": { "version": "..." } | SDK version (determines -- separator behavior) | | .csproj | <TestingPlatformDotnetTestSupport>true | MTP on SDK 8/9 | | .csproj | MSTest, xunit.v3, NUnit, TUnit packages | Framework identity | | .csproj | Microsoft.NET.Test.Sdk + test adapter | VSTest (unless overridden by MTP signals above) | | .csproj | <TargetFrameworks> (plural) | Multi-TFM — may need --framework | | Directory.Build.props | <TestingPlatformDotnetTestSupport>true | MTP on SDK 8/9 (often set here, not in .csproj) | | Directory.Packages.props | Centrally managed test package versions | Framework identity for CPM repos |
Quick detection summary:
| Signal | Means | |--------|-------| | global.json has "test": { "runner": "Microsoft.Testing.Platform" } | MTP on SDK 10+ — pass args directly, no -- | | <TestingPlatformDotnetTestSupport>true in csproj or Directory.Build.props | MTP on SDK 8/9 — pass args after -- | | Neither signal present | VSTest |
Step 2: Run tests
#### VSTest (any .NET SDK version)
dotnet test [<PROJECT> | <SOLUTION> | <DIRECTORY> | <DLL> | <EXE>]
Common flags:
| Flag | Description | |------|-------------| | --framework <TFM> | Target a specific framework in multi-TFM projects (e.g., net8.0) | | --no-build | Skip build, use previously built output | | --filter <EXPRESSION> | Run selected tests (see Step 3) | | --logger trx | Generate TRX results file | | --collect "Code Coverage" | Collect code coverage using Microsoft Code Coverage (built-in, always available) | | --blame | Enable blame mode to detect tests that crash the host | | --blame-crash | Collect a crash dump when the test host crashes | | --blame-hang-timeout <duration> | Abort test if it hangs longer than duration (e.g., 5min) | | -v <level> | Verbosity: quiet, minimal, normal, detailed, diagnostic |
#### MTP with .NET SDK 8 or 9
With <TestingPlatformDotnetTestSupport>true</TestingPlatformDotnetTestSupport>, dotnet test bridges to MTP but uses VSTest-style argument parsing. MTP-specific arguments must be passed after --:
dotnet test [<PROJECT> | <SOLUTION> | <DIRECTORY> | <DLL> | <EXE>] -- <MTP_ARGUMENTS>
#### MTP with .NET SDK 10+
With the global.json runner set to Microsoft.Testing.Platform, dotnet test natively understands MTP arguments without --:
dotnet test
[--project <PROJECT_OR_DIRECTORY>]
[--solution <SOLUTION_OR_DIRECTORY>]
[--test-modules <EXPRESSION>]
[<MTP_ARGUMENTS>]
Examples:
# Run all tests in a project
dotnet test --project path/to/MyTests.csproj
# Run all tests in a directory containing a project
dotnet test --project path/to/
# Run all tests in a solution (sln, slnf, slnx)
dotnet test --solution path/to/MySolution.sln
dotnet test --solution path/to/MySolution.slnf
dotnet test --solution path/to/MySolution.slnx
# Run all tests in a directory containing a solution
dotnet test --solution path/to/
# Run with MTP flags
dotnet test --project path/to/MyTests.csproj --report-trx --blame-hang-timeout 5min
> Note: The .NET 10+ dotnet test syntax does not accept a bare positional argument like the VSTest syntax. Use --project, --solution, or --test-modules to specify the target.
#### Common MTP flags
These flags apply to MTP on both SDK versions. On SDK 8/9, pass after --; on SDK 10+, pass directly.
> Important: dotnet test/MSBuild flags such as --framework, --no-build, --configuration, and --verbosity are consumed by dotnet test itself (they drive restore/build/host selection) and always go BEFORE `--`, regardless of platform or SDK. Only MTP test-platform arguments go after -- on SDK 8/9. For example: dotnet test --framework net9.0 -- --report-trx (built-in flag before --, MTP extension flag after).
Built-in flags (always available):
| Flag | Description | |------|-------------| | --results-directory <DIR> | Directory for test result output | | --diagnostic | Enable diagnostic logging for the test platform | | --diagnostic-output-directory <DIR> | Directory for diagnostic log output |
Extension-dependent flags (require the corresponding extension package to be registered):
| Flag | Requires | Description | |------|----------|-------------| | --filter <EXPRESSION> | Framework-specific (not all frameworks support this) | Run selected tests (see Step 3) | | --report-trx | Microsoft.Testing.Extensions.TrxReport | Generate TRX results file | | --report-trx-filename <FILE> | Microsoft.Testing.Extensions.TrxReport | Set TRX output filename | | --blame-hang-timeout <duration> | Microsoft.Testing.Extensions.HangDump | Abort test if it hangs longer than duration (e.g., 5min) | | --blame-crash | Microsoft.Testing.Extensions.CrashDump | Collect a crash dump when the test host crashes | | --coverage | Microsoft.Testing.Extensions.CodeCoverage | Collect code coverage using Microsoft Code Coverage |
> Some frameworks (e.g., MSTest) bundle common extensions by default. Others may require explicit package references. If a flag is not recognized, check that the corresponding extension package is referenced in the project.
#### Alternative MTP invocations
MTP test projects are standalone executables. Beyond dotnet test, they can be run directly:
# Build and run
dotnet run --project <PROJECT_PATH>
# Run a previously built DLL
dotnet exec <PATH_TO_DLL>
# Run the executable directly (Windows)
<PATH_TO_EXE>
These alternative invocations accept MTP command line arguments directly (no -- separator needed).
Step 3: Run filtered tests
See the filter-syntax skill for the complete filter syntax for each platform and framework combination. Key points:
- VSTest (MSTest, xUnit v2, NUnit):
dotnet test --filter <EXPRESSION>with=,!=,~,!~operators - MTP -- MSTest and NUnit: Same
--filtersyntax as VSTest; pass after--on SDK 8/9, directly on SDK 10+ - MTP -- xUnit v3: Uses
--filter-class,--filter-method,--filter-trait(not VSTest expression syntax). For a single combined expression (e.g., a class-name pattern AND a trait), use--filter-querywith the xUnit v3 query filter language: path segments/<assembly>/<namespace>/<class>/<method>with*wildcards and a[Trait=Value]qualifier — for exampledotnet test -- --filter-query "/*/*/*IntegrationTests*/*[Category=Smoke]". See thefilter-syntaxskill for the full query language. - MTP -- TUnit: Uses
--treenode-filterwith path-based syntax
#### When the user names a test category, trait, or group
When the prompt names a subset of tests by category (e.g., "integration tests", "unit tests", "smoke tests", "fast tests"), do not run all tests — translate the user's vocabulary into the platform-appropriate filter:
- Inspect the test source files for filter-attribute annotations that match the named group:
| Framework | Attribute | Filter property | |-----------|-----------|-----------------| | MSTest | [TestCategory("Integration")] | TestCategory | | NUnit | [Category("Integration")] | TestCategory (mapped) | | xUnit v2 | [Trait("Category", "Integration")] | Category | | xUnit v3 | [Trait("Category", "Integration")] | Category (use --filter-trait) | | TUnit | [Category("Integration")] | Category |
- Build the filter expression and combine it with the platform-correct invocation. For "run the integration tests" against an MSTest project:
| Platform | SDK | Command | |----------|-----|---------| | VSTest (MSTest) | any | dotnet test --filter "TestCategory=Integration" | | MTP (MSTest) | 8 or 9 | dotnet test -- --filter "TestCategory=Integration" | | MTP (MSTest) | 10+ | dotnet test --filter "TestCategory=Integration" | | MTP (xUnit v3) | 8 or 9 | dotnet test -- --filter-trait "Category=Integration" | | MTP (xUnit v3) | 10+ | dotnet test --filter-trait "Category=Integration" | | MTP (TUnit) | 8 or 9 | dotnet test -- --treenode-filter "/*/*/*/*[Category=Integration]" |
- If you cannot find a matching attribute, ask the user to confirm the category name or fall back to a name-pattern filter (e.g.,
--filter "FullyQualifiedName~Integration").
Related skills
Write, run, or repair .NET tests that use MSTest.
Write, run, or repair .NET tests that use NUnit.