
Testing in .NET has historically been associated with VSTest. That choice was reasonable for a long time because VSTest offered broad tooling support, deep IDE integration and a familiar execution model for MSTest, xUnit and NUnit projects. But the .NET ecosystem has changed. Native AOT, trimming, simplified deployment models, executable-first workflows and more explicit build-time configuration have pushed the platform toward models that do not fit particularly well with the older test infrastructure.
Microsoft Testing Platform, often abbreviated as MTP, is Microsoft’s answer to that shift. It is not a new unit testing framework like MSTest, xUnit or NUnit. It is a new test platform: the runtime and orchestration layer that discovers, hosts and executes tests, integrates with tools and exposes extension points.
That distinction matters because much of the confusion around the topic comes from mixing up framework and platform concerns. MSTest, NUnit, xUnit and TUnit define how tests are written. Microsoft Testing Platform defines how those tests are run.
This article explains what Microsoft Testing Platform is, what is actually new, why Microsoft introduced it, where the advantages are real, where migration friction can appear and how the platform looks in practice with concrete samples. The goal is to make the topic accessible for beginners without flattening the details that matter to experienced .NET engineers.
Introduction
In .NET, a test setup has two main layers:
- The test framework, such as MSTest, NUnit, xUnit.net or TUnit.
- The test platform, which discovers tests, runs them and communicates with CLI tools, IDEs and CI systems.
For many years, VSTest was the default platform. Microsoft Testing Platform is a newer alternative designed for modern .NET scenarios. According to the official documentation, it is a lightweight and portable alternative to VSTest and is embedded directly in the test project itself.
That last point changes the mental model significantly. Instead of relying on a more centralized runtime setup, the test runner becomes part of the test application. In practice, this means that MTP-based test projects behave more like regular executables. They can be run directly, via dotnet run, via dotnet exec, through IDE integration and in CI, while still exposing testing-specific functionality.
The official platform overview describes several architectural pillars behind this design:
- determinism
- runtime transparency
- compile-time registration of extensions
- zero dependencies in the platform core
- hostability in any .NET application
- support for modern .NET form factors, including Native AOT scenarios
- a deliberately performance-oriented orchestration model
That is the conceptual baseline for everything else in the platform.
What Is New and Why
Microsoft Testing Platform is not simply a rebranding of VSTest. The differences are architectural.
The platform is embedded into the test project
The most visible difference is that the runner is embedded in the test project. The official documentation explicitly states that there are no extra application dependencies such as vstest.console required to run tests, even though dotnet test can still be used.
For beginners, this can be summarized as follows: an MTP-based test project behaves more like a normal .NET application with test semantics attached to it.
For advanced users, the more important implication is that the execution model is less dependent on historical layering decisions in VSTest.
Compile-time registration replaces more dynamic behavior
A core design goal of MTP is determinism. Extensions are registered at compile time instead of relying on a more dynamic discovery model. This is intended to reduce context-dependent behavior and make local execution, CI execution and IDE execution more consistent.
That change is also one of the reasons Microsoft emphasizes runtime transparency. The platform avoids interfering with test framework code through reflection-heavy coordination, isolated loading models or custom assembly resolution behavior where possible.
The platform is designed around modern .NET constraints
The official comparison material highlights a few scenarios where MTP is clearly the better fit:
- Native AOT and trimming related test execution scenarios
- executable-first workflows such as
dotnet run - stricter and more explicit defaults
- modern extension composition through NuGet packages
These are not niche details. They are signals that the test platform is being aligned with the rest of the current .NET engineering model.
The ecosystem is moving, but not all tools move at the same speed
This is where nuance becomes important. Microsoft Testing Platform is supported in Visual Studio and Visual Studio Code scenarios, but VSTest still has the broader compatibility history across the ecosystem. Microsoft says this directly in the platform comparison: VSTest remains the longer-established option and some third-party integrations can still lag behind MTP.
That means the new platform exists for strong architectural reasons, but migration should still be decided based on the shape of the solution and the surrounding tooling.
Benefits
The benefits of Microsoft Testing Platform are easiest to understand when separated into practical categories.
1. A lighter execution model
Microsoft describes MTP as lightweight and the MSTest documentation goes further by stating that the MSTest runner built on MTP is more lightweight and faster than VSTest.
This should not be interpreted as a universal benchmark claim for every solution and every framework combination. But it is a strong signal about the platform’s design goals: less runtime complexity, fewer moving parts and less orchestration overhead.
2. Better alignment with modern .NET application behavior
Because MTP-based test projects behave like executables, they fit naturally into workflows that already exist for regular applications:
- direct execution of the built test binary
dotnet runfor local executiondotnet execfor explicit runtime execution- repository-level configuration through MSBuild properties and
global.json
This reduces the conceptual gap between “application projects” and “test projects”.
3. Deterministic extension registration
The platform uses compile-time extension registration and transitive MSBuild integration. For many setups, installing an extension NuGet package is enough for it to be auto-detected and auto-registered.
That is an important maintainability gain. Instead of depending on loosely coordinated runtime discovery, the platform can describe more of its own behavior at build time.
4. Better fit for Native AOT and future .NET form factors
The test platform overview explicitly positions MTP as the right choice when Native AOT or trimming-related scenarios matter. That alone makes it strategically important for teams that want their tooling to evolve with the runtime.
5. More explicit behavior in edge cases
MTP is stricter in some situations. One example from the migration guide is especially important: if a test assembly runs zero tests, VSTest exits successfully, while MTP fails with exit code 8.
This is not a regression in itself. It is a different philosophy. Silent success for zero discovered tests can hide configuration mistakes, missing filters or broken discovery logic. Failing early is often the safer behavior in CI.
6. Extension-driven reporting and diagnostics
In VSTest, capabilities such as logging and collection were often consumed through generalized switches like --logger and --collect. In MTP, those concerns are modeled more explicitly through extension-specific options.
That design is more modular, but it also requires more deliberate migration work because old commands do not always translate one-to-one.
Practical Samples
The most effective way to understand MTP is to look at concrete project shapes.
Sample 1: A new MSTest project using MSTest.Sdk
The recommended approach for new MSTest projects is MSTest.Sdk. Microsoft states that this SDK provides the first-class MSTest experience and uses Microsoft Testing Platform by default unless explicitly configured otherwise.
1<Project Sdk="MSTest.Sdk/4.1.0">
2
3 <PropertyGroup>
4 <TargetFramework>net10.0</TargetFramework>
5 <ImplicitUsings>enable</ImplicitUsings>
6 <Nullable>enable</Nullable>
7 </PropertyGroup>
8
9</Project>
This is the cleanest entry point for a new codebase because the platform and runner choices are aligned from the beginning.
Sample 2: Opting an existing MSTest project into MTP
For an existing MSTest project that still uses the classic SDK style, the migration can be introduced through explicit MSBuild properties.
1<Project Sdk="Microsoft.NET.Sdk">
2
3 <PropertyGroup>
4 <TargetFramework>net10.0</TargetFramework>
5 <ImplicitUsings>enable</ImplicitUsings>
6 <Nullable>enable</Nullable>
7
8 <OutputType>Exe</OutputType>
9 <EnableMSTestRunner>true</EnableMSTestRunner>
10 <TestingPlatformDotnetTestSupport>true</TestingPlatformDotnetTestSupport>
11 <TestingPlatformShowTestsFailure>true</TestingPlatformShowTestsFailure>
12 </PropertyGroup>
13
14 <ItemGroup>
15 <PackageReference Include="MSTest" Version="4.1.0" />
16 </ItemGroup>
17
18</Project>
Three things are worth calling out here:
OutputTypechanges toExebecause the test project becomes executable.EnableMSTestRunneropts the project into the MSTest runner on top of MTP.TestingPlatformDotnetTestSupportis relevant whendotnet testis used through the VSTest-based mode available in older SDK flows.
Sample 3: Repository-wide configuration in Directory.Build.props
Microsoft recommends placing these properties in Directory.Build.props rather than copying them into every test project. That advice is important because mixing VSTest-based and MTP-based .NET test projects in the same solution is explicitly documented as unsupported.
1<Project>
2
3 <PropertyGroup>
4 <EnableMSTestRunner>true</EnableMSTestRunner>
5 <TestingPlatformDotnetTestSupport>true</TestingPlatformDotnetTestSupport>
6 <TestingPlatformShowTestsFailure>true</TestingPlatformShowTestsFailure>
7 </PropertyGroup>
8
9</Project>
For larger repositories, this is usually the safer migration shape because it reduces configuration drift.
Sample 4: Native MTP mode for dotnet test in .NET 10+
Starting with the .NET 10 SDK, dotnet test can run in a native Microsoft Testing Platform mode. The official migration guide explains that this is enabled via global.json.
1{
2 "test": {
3 "runner": "Microsoft.Testing.Platform"
4 }
5}
This is a meaningful change because the older compatibility mode relied on VSTest infrastructure underneath dotnet test. In native MTP mode, the command line model becomes cleaner and the extra argument separator is no longer required.
Sample 5: Running tests directly
An MTP-enabled MSTest project can be executed in several ways:
1dotnet run --project Contoso.MyTests -- --filter "FullyQualifiedName~UnitTest1|TestCategory=CategoryA"
1dotnet exec Contoso.MyTests.dll --settings config.runsettings
1dotnet Contoso.MyTests.dll --settings config.runsettings
1Contoso.MyTests.exe --settings config.runsettings
This executable-first model is one of the most concrete differences from historical VSTest-centric habits.
Sample 6: TRX reporting and code coverage in MTP style
In VSTest, old command lines often looked like this:
1dotnet test --logger trx --collect "Code Coverage;Format=cobertura"
In MTP, the model becomes extension-specific. The migration guide maps those concepts like this:
1dotnet test --report-trx --coverage --coverage-output-format cobertura
When the compatibility layer for older dotnet test behavior is used, the extra -- separator is required:
1dotnet test -- --report-trx --coverage --coverage-output-format cobertura
That is more than a syntax change. It reflects the underlying architectural shift from generalized VSTest extensibility to explicit MTP extension commands.
Migration
Migration is straightforward in the simple case and subtle in the real-world case.
Step 1: Decide whether migration is appropriate now
The official platform comparison is pragmatic about trade-offs.
MTP is a strong fit when:
- Native AOT or trimming-related scenarios matter
- test projects should behave like normal executables
- stricter and more deterministic behavior is preferred
- the repository is mostly .NET and does not rely on mixed-language VSTest adapters
VSTest can still be the better choice when:
- established third-party tooling is heavily coupled to VSTest
- mixed-language adapter scenarios matter
- a solution depends on project types not currently supported by MTP
Migration is not a mandatory modernization exercise. It is a platform decision.
Step 2: Standardize at repository level
Microsoft explicitly recommends not mixing VSTest and MTP-based .NET test projects in the same solution or run configuration. This is one of the most important migration rules.
If migration happens, it should usually happen at the repository or solution boundary, not project-by-project in a partially migrated state.
Step 3: Update the framework-specific opt-in
The migration guide lists the framework-level switches:
- MSTest:
EnableMSTestRunner - NUnit:
EnableNUnitRunner - xUnit.net v3:
UseMicrosoftTestingPlatformRunner
All test projects also need:
OutputTypeset toExe
That is the baseline configuration change across frameworks.
Step 4: Decide how dotnet test is supposed to work
This is where many migrations become confusing.
For .NET 9 and earlier, MTP support in dotnet test is not native. It is built on top of the older VSTest mode, which means:
TestingPlatformDotnetTestSupportmust be enabled- platform arguments must be separated with
--
Example:
1dotnet test --no-build -- --list-tests
For .NET 10 and later, native MTP mode can be enabled in global.json and the extra -- is no longer needed.
That means the same repository can have very different command line ergonomics depending on the SDK strategy.
Step 5: Rewrite VSTest-specific arguments
This is the part that tends to be underestimated.
Some arguments map cleanly:
| VSTest | Microsoft Testing Platform |
|---|---|
--list-tests | --list-tests |
--diag | --diagnostic |
--results-directory | --results-directory |
Some arguments change meaning or extension model:
| VSTest | Microsoft Testing Platform |
|---|---|
--logger trx | --report-trx |
--collect "Code Coverage;Format=cobertura" | --coverage --coverage-output-format cobertura |
--blame-crash | --crashdump with the relevant extension |
--blame-hang | --hangdump with the relevant extension |
Some behaviors depend on the selected framework:
- MSTest and NUnit can continue using familiar filter formats
- xUnit on MTP uses the xUnit v3 query/filter model instead of the VSTest filter format
This is precisely why migration work should include CI scripts, local developer commands, IDE assumptions and documentation, not only .csproj changes.
Step 6: Account for behavioral differences
At least three differences are important enough to check during migration:
- Zero discovered tests can fail the build with exit code
8. - Some output handling behaviors differ because MTP preserves console encoding more explicitly in scenarios where VSTest isolation historically behaved differently.
- Old RunSettings usage is no longer a core platform concept. MTP replaces that with
testconfig.json, although MSTest and NUnit still support--settingsfor existing RunSettings-based workflows.
These are not theoretical details. They affect CI reliability, test discovery expectations and failure analysis.
Step 7: Update CI pipelines deliberately
The migration guide specifically calls out Azure DevOps. If a pipeline still uses the VSTest task, Microsoft recommends moving to the .NET CLI task.
A minimal Azure DevOps style example for TRX reporting with MTP looks like this:
1- task: DotNetCoreCLI@2
2 displayName: Run unit tests
3 inputs:
4 command: test
5 arguments: '-- --report-trx --results-directory $(Agent.TempDirectory)'
For GitHub Actions or other CI systems, the same principle applies: MTP changes test arguments and in some cases exit-code expectations. Pipelines should be reviewed as part of the migration, not after it.
Result: Is It Actually Faster?
This is the question most teams eventually ask.
The documented answer is careful but meaningful.
Microsoft describes the platform as lightweight and performance-oriented. The MSTest runner documentation makes the clearest statement: the MSTest runner built on MTP is more lightweight and faster than VSTest.
That is the official claim. But it does not automatically answer how much faster a specific solution will become.
What can be stated confidently
The following points are grounded in the documentation:
- MTP is designed to reduce orchestration overhead.
- The platform avoids some of the older dynamic behaviors that made the VSTest model more complex.
- Extension registration is more explicit and build-time driven.
- The runtime model is shaped for modern .NET execution scenarios.
All of those factors are consistent with lower startup and coordination overhead.
What remains project-specific
Actual end-to-end execution time still depends on many variables:
- test framework in use
- number of test projects
- extension packages in the run
- amount of console or diagnostic output
- code coverage settings
- CI machine performance
- whether tests are CPU-bound, I/O-bound or process-heavy
For many repositories, the most realistic expectation is not “all tests suddenly run dramatically faster” but rather a combination of:
- somewhat lower runner overhead
- a cleaner execution model
- better consistency between local and CI behavior
- simpler long-term alignment with modern .NET scenarios
That is still valuable. In many engineering organizations, determinism and configuration clarity save more time than a small raw execution-time gain.
A practical conclusion on speed
If the question is whether MTP can be faster than VSTest, the answer is yes and Microsoft explicitly says so for the MSTest runner.
If the question is whether every repository will see a dramatic measurable improvement, the answer is no. The main benefits are architectural first, operational second and raw speed third.
That ordering is important because it keeps migration decisions honest.
Where Migration Can Fail
The most common failure patterns are structural rather than syntactic.
Mixing platforms in one solution
This is explicitly unsupported for .NET test projects in the same solution or run configuration. A half-migrated repository can behave worse than a repository that stays entirely on VSTest for one more release cycle.
Assuming dotnet test behaves the same everywhere
The command line model differs between the compatibility path used by older SDK workflows and the native MTP path in .NET 10+. This affects documentation, local scripts and CI definitions.
Forgetting extensions during command migration
Commands like --report-trx, --coverage, --crashdump or --hangdump depend on the relevant MTP extensions being installed. Old VSTest habits often hide this dependency behind more generalized arguments.
Treating filter migration as trivial
MSTest and NUnit preserve more continuity here. xUnit on MTP does not. Any solution with heavy --filter usage in xUnit should budget time for command rewriting and documentation updates.
Ignoring stricter exit behavior
Teams that accidentally rely on “zero tests is still success” semantics often discover this only after CI begins to fail. In most cases that failure is useful, but it still has to be planned for.
Conclusion
Microsoft Testing Platform is one of the more important infrastructure changes in the modern .NET testing story because it updates the test runtime model rather than merely adding new syntax on top of old assumptions.
For beginners, the core message is simple: MTP is the engine that runs tests, not the framework used to write them. It makes test projects behave more like normal .NET executables and introduces a more explicit model for configuration, extensions and execution.
For advanced teams, the more interesting message is architectural: MTP is designed around determinism, compile-time composition, modern .NET deployment shapes and a lighter orchestration model. That makes it especially relevant for repositories that want to reduce legacy testing friction and align with the direction of the .NET runtime.
Migration is not always urgent and VSTest remains a valid choice when ecosystem compatibility is still the dominant requirement. But for new test suites or for .NET-heavy repositories that want a cleaner and more future-aligned platform, Microsoft Testing Platform is increasingly the more coherent choice.
The strongest reason to adopt it is not that it promises magic speed gains. The strongest reason is that it gives .NET testing a runtime model that better matches how the platform itself now works.
Related articles

Mar 17, 2026 · 15 min read
GitHub Copilot - Custom Agents for Full-Stack Teams: A Practical Operating Model for .NET, React and Azure
GitHub Copilot custom agents allow teams to define specialized AI assistants, each with its own role, tool access and behavioral boundaries. …

Mar 10, 2026 · 15 min read
.NET NuGet Trusted Publishing with GitHub Actions
Publishing NuGet packages has traditionally required one uncomfortable compromise: a long-lived API key had to exist somewhere in the …

Feb 09, 2026 · 4 min read
Create a Local SQL Server Database File with .NET
Local SQL Server database files provide a pragmatic way to keep a real SQL Server engine close to the application without provisioning a …
Let's Work Together
Looking for an experienced Platform Architect or Engineer for your next project? Whether it's cloud migration, platform modernization or building new solutions from scratch - I'm here to help you succeed.

Comments