migrate-vstest-to-mtp

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

VSTest -> Microsoft.Testing.Platform Migration

从VSTest迁移至Microsoft.Testing.Platform

Migrate a .NET test solution from VSTest to Microsoft.Testing.Platform (MTP). The outcome is a solution where all test projects run on MTP,
dotnet test
works correctly, and CI/CD pipelines are updated.
Important: Do not mix VSTest-based and MTP-based .NET test projects in the same solution or run configuration -- this is an unsupported scenario.
将.NET测试解决方案从VSTest迁移至Microsoft.Testing.Platform(简称MTP)。迁移完成后,解决方案中的所有测试项目均可在MTP上运行,
dotnet test
命令可正常工作,且CI/CD流水线已完成更新。
重要提示:请勿在同一解决方案或运行配置中混合使用基于VSTest和基于MTP的.NET测试项目——这属于不支持的场景。

When to Use

适用场景

  • Switching from VSTest to Microsoft.Testing.Platform for any supported test framework
  • Enabling
    dotnet run
    /
    dotnet watch
    / direct executable execution for test projects
  • Enabling Native AOT or trimmed test execution
  • Replacing
    vstest.console.exe
    with
    dotnet test
    on MTP
  • Updating CI/CD pipelines from the VSTest task to the .NET Core CLI task
  • Updating
    dotnet test
    arguments from VSTest syntax to MTP syntax
  • 为任意受支持的测试框架从VSTest切换至Microsoft.Testing.Platform
  • 为测试项目启用
    dotnet run
    /
    dotnet watch
    / 直接执行可执行文件的功能
  • 启用Native AOT或裁剪后的测试执行
  • 用基于MTP的
    dotnet test
    替代
    vstest.console.exe
  • 将CI/CD流水线从VSTest任务更新为.NET Core CLI任务
  • dotnet test
    的参数从VSTest语法转换为MTP语法

When Not to Use

不适用场景

  • The project already runs on Microsoft.Testing.Platform and there is no remaining MTP behavioral difference to resolve (e.g., exit code 8 for zero tests discovered)
  • Migrating between test frameworks (e.g., MSTest to xUnit.net) -- different effort entirely
  • The project builds UWP or packaged WinUI test projects -- MTP does not support these yet
  • The solution mixes .NET and non-.NET test adapters (e.g., JavaScript or C++ adapters) -- VSTest is required
  • Upgrading MSTest versions -- use
    migrate-mstest-v1v2-to-v3
    or
    migrate-mstest-v3-to-v4
  • 项目已在Microsoft.Testing.Platform上运行,且不存在需要解决的MTP行为差异(例如,未发现测试时返回退出代码8)
  • 测试框架间迁移(如从MSTest迁移至xUnit.net)——这属于完全不同的工作内容
  • 项目为UWP或打包的WinUI测试项目——MTP目前不支持这类项目
  • 解决方案混合了.NET与非.NET测试适配器(如JavaScript或C++适配器)——必须使用VSTest
  • MSTest版本升级——请使用
    migrate-mstest-v1v2-to-v3
    migrate-mstest-v3-to-v4
    工具

Inputs

输入项

InputRequiredDescription
Project or solution pathYesThe
.csproj
,
.sln
, or
.slnx
entry point containing test projects
Test frameworkNoMSTest, NUnit, xUnit.net v2, or xUnit.net v3. Auto-detected from package references
.NET SDK versionNoDetermines
dotnet test
integration mode. Auto-detected via
dotnet --version
CI/CD pipeline filesNoPaths to pipeline definitions that invoke
vstest.console
or
dotnet test
输入项是否必填描述
项目或解决方案路径包含测试项目的
.csproj
.sln
.slnx
入口文件
测试框架MSTest、NUnit、xUnit.net v2或xUnit.net v3。将从包引用中自动检测
.NET SDK版本决定
dotnet test
的集成模式。将通过
dotnet --version
自动检测
CI/CD流水线文件调用
vstest.console
dotnet test
的流水线定义文件路径

Workflow

工作流程

Step 1: Assess the solution

步骤1:评估解决方案

  1. Identify the test framework for each test project -- see the
    platform-detection
    skill for the package-to-framework mapping. Key indicators:
    • MSTest: References
      MSTest
      or
      MSTest.TestAdapter
      , or uses
      MSTest.Sdk
      (with
      <IsTestApplication>
      not set to
      false
      ). Note:
      MSTest.TestFramework
      alone is a library dependency, not a test project.
    • NUnit: References
      NUnit3TestAdapter
    • xUnit.net: References
      xunit
      and
      xunit.runner.visualstudio
  2. Check the .NET SDK version (
    dotnet --version
    ) -- this determines how
    dotnet test
    integrates with MTP
  3. Check whether a
    Directory.Build.props
    file exists at the solution or repo root -- all MTP properties should go there for consistency
  4. Check for
    vstest.console.exe
    usage in CI scripts or pipeline definitions
  5. Check for VSTest-specific
    dotnet test
    arguments in CI scripts:
    --filter
    ,
    --logger
    ,
    --collect
    ,
    --settings
    ,
    --blame*
  6. Run
    dotnet test
    to establish a baseline of test pass/fail counts
  1. 确定每个测试项目的测试框架——可参考
    platform-detection
    工具中的包与框架映射关系。关键识别标志:
    • MSTest:引用了
      MSTest
      MSTest.TestAdapter
      ,或使用了
      MSTest.Sdk
      (且
      <IsTestApplication>
      未设置为
      false
      )。注意:仅引用
      MSTest.TestFramework
      属于库依赖,并非测试项目。
    • NUnit:引用了
      NUnit3TestAdapter
    • xUnit.net:引用了
      xunit
      xunit.runner.visualstudio
  2. 检查.NET SDK版本(
    dotnet --version
    )——这将决定
    dotnet test
    与MTP的集成方式
  3. 检查解决方案或仓库根目录是否存在
    Directory.Build.props
    文件——所有MTP属性应统一配置在此文件中
  4. 检查CI脚本或流水线定义中是否使用了
    vstest.console.exe
  5. 检查CI脚本中是否存在VSTest专属的
    dotnet test
    参数:
    --filter
    --logger
    --collect
    --settings
    --blame*
  6. 运行
    dotnet test
    以建立测试通过/失败数量的基准值

Step 2: Set up Directory.Build.props

步骤2:配置Directory.Build.props

Critical: Set MTP runner properties in
Directory.Build.props
at the solution or repo root whenever possible, rather than per-project. This prevents inconsistent configuration where some projects use VSTest and others use MTP (an unsupported scenario). Note: MTP also requires test projects to have
<OutputType>Exe</OutputType>
. Only
MSTest.Sdk
sets this automatically. For all other setups (MSTest NuGet packages with
EnableMSTestRunner
, NUnit with
EnableNUnitRunner
, xUnit.net with
YTest.MTP.XUnit2
), prefer setting
<OutputType>Exe</OutputType>
centrally in
Directory.Build.props
with a condition that targets only test projects. If you cannot reliably target only test projects from
Directory.Build.props
, setting
<OutputType>Exe</OutputType>
per-project is an acceptable exception.
Conditioning in
Directory.Build.props
: Do NOT use
Condition="'$(IsTestProject)' == 'true'"
--
IsTestProject
is set by the test SDK targets later in evaluation and is not available when
Directory.Build.props
is imported. Use a property that is available early, such as
MSBuildProjectName
, to target test projects by naming convention. For example, if all test projects end in
.Tests
:
xml
<PropertyGroup Condition="$(MSBuildProjectName.EndsWith('.Tests'))">
  <OutputType>Exe</OutputType>
</PropertyGroup>
Adjust the condition (e.g.,
.EndsWith('Tests')
,
.Contains('.Test')
) to match the test project naming convention used in the repository.
关键提示:尽可能在解决方案或仓库根目录的
Directory.Build.props
中设置MTP运行器属性,而非逐个项目配置。这可避免部分项目使用VSTest、部分使用MTP的不一致配置(属于不支持的场景)。 注意:MTP还要求测试项目设置
<OutputType>Exe</OutputType>
。仅
MSTest.Sdk
会自动设置该属性。对于其他所有配置(使用
EnableMSTestRunner
的MSTest NuGet包、使用
EnableNUnitRunner
的NUnit、使用
YTest.MTP.XUnit2
的xUnit.net),建议在
Directory.Build.props
中通过条件仅针对测试项目集中设置
<OutputType>Exe</OutputType>
。如果无法通过
Directory.Build.props
可靠地仅定位测试项目,则逐个项目设置
<OutputType>Exe</OutputType>
是可接受的例外情况。
Directory.Build.props中的条件设置:请勿使用
Condition="'$(IsTestProject)' == 'true'"
——
IsTestProject
是在评估后期由测试SDK目标设置的,在导入
Directory.Build.props
时尚未可用。请使用早期可用的属性,例如
MSBuildProjectName
,通过命名约定定位测试项目。例如,如果所有测试项目均以
.Tests
结尾:
xml
<PropertyGroup Condition="$(MSBuildProjectName.EndsWith('.Tests'))">
  <OutputType>Exe</OutputType>
</PropertyGroup>
根据仓库中使用的测试项目命名约定调整条件(例如
.EndsWith('Tests')
.Contains('.Test')
)。

Step 3: Enable the framework-specific MTP runner

步骤3:启用特定框架的MTP运行器

Each framework has its own opt-in property. Add these in
Directory.Build.props
for consistency.
每个框架都有其专属的启用属性。为保持一致性,建议将这些属性添加到
Directory.Build.props
中。

MSTest

MSTest

Option A -- MSTest NuGet packages (3.2.0+):
xml
<PropertyGroup>
  <EnableMSTestRunner>true</EnableMSTestRunner>
  <OutputType>Exe</OutputType>
</PropertyGroup>
Ensure the project references MSTest 3.2.0 or later. If the version is already 3.2.0+, no MSTest version upgrade is needed for MTP migration.
Option B -- MSTest.Sdk:
When using
MSTest.Sdk
, MTP is enabled by default -- no
EnableMSTestRunner
or
OutputType Exe
property is needed (the SDK sets both automatically). The only action is: if the project has
<UseVSTest>true</UseVSTest>
, remove it. That property forces the project to use VSTest instead of MTP.
选项A——MSTest NuGet包(3.2.0及以上版本):
xml
<PropertyGroup>
  <EnableMSTestRunner>true</EnableMSTestRunner>
  <OutputType>Exe</OutputType>
</PropertyGroup>
确保项目引用的MSTest版本为3.2.0或更高。如果版本已满足要求,则无需升级MSTest版本即可完成MTP迁移。
选项B——MSTest.Sdk:
使用
MSTest.Sdk
时,MTP默认已启用——无需设置
EnableMSTestRunner
OutputType Exe
属性(SDK会自动设置这两项)。仅需执行的操作是:如果项目中存在
<UseVSTest>true</UseVSTest>
,请移除该配置。此属性会强制项目使用VSTest而非MTP。

NUnit

NUnit

Requires
NUnit3TestAdapter
5.0.0 or later.
  1. Update
    NUnit3TestAdapter
    to 5.0.0+:
xml
<PackageReference Include="NUnit3TestAdapter" Version="5.0.0" />
  1. Enable the NUnit runner:
xml
<PropertyGroup>
  <EnableNUnitRunner>true</EnableNUnitRunner>
  <OutputType>Exe</OutputType>
</PropertyGroup>
要求
NUnit3TestAdapter
版本为5.0.0或更高。
  1. NUnit3TestAdapter
    更新至5.0.0及以上版本:
xml
<PackageReference Include="NUnit3TestAdapter" Version="5.0.0" />
  1. 启用NUnit运行器:
xml
<PropertyGroup>
  <EnableNUnitRunner>true</EnableNUnitRunner>
  <OutputType>Exe</OutputType>
</PropertyGroup>

xUnit.net

xUnit.net

Add a reference to
YTest.MTP.XUnit2
-- this package provides MTP support for xUnit.net v2 projects without requiring an upgrade to xunit.v3. You must also set
OutputType
to
Exe
:
xml
<PackageReference Include="YTest.MTP.XUnit2" Version="0.4.0" />
xml
<PropertyGroup>
  <OutputType>Exe</OutputType>
</PropertyGroup>
Note:
YTest.MTP.XUnit2
preserves the VSTest
--filter
syntax, so no filter migration is needed for xUnit.net v2. It also supports
--settings
for runsettings (xunit-specific configurations only),
xunit.runner.json
, TRX reporting via
--report-trx
, and
--treenode-filter
.
添加对
YTest.MTP.XUnit2
的引用——该包为xUnit.net v2项目提供MTP支持,无需升级至xunit.v3。同时必须将
OutputType
设置为
Exe
xml
<PackageReference Include="YTest.MTP.XUnit2" Version="0.4.0" />
xml
<PropertyGroup>
  <OutputType>Exe</OutputType>
</PropertyGroup>
注意
YTest.MTP.XUnit2
保留了VSTest的
--filter
语法,因此xUnit.net v2无需进行过滤器迁移。它还支持
--settings
(仅针对xunit特定配置的runsettings)、
xunit.runner.json
、通过
--report-trx
生成TRX报告,以及
--treenode-filter

xUnit.net v3

xUnit.net v3

xUnit.net v3 (
xunit.v3
package) has built-in MTP support. Enable it with:
xml
<PropertyGroup>
  <UseMicrosoftTestingPlatformRunner>true</UseMicrosoftTestingPlatformRunner>
</PropertyGroup>
Important: xUnit.net v3 on MTP does NOT support the VSTest
--filter
syntax. You must translate filters to xUnit.net v3's native filter options (see Step 5).
xUnit.net v3(
xunit.v3
包)原生支持MTP。通过以下配置启用:
xml
<PropertyGroup>
  <UseMicrosoftTestingPlatformRunner>true</UseMicrosoftTestingPlatformRunner>
</PropertyGroup>
重要提示:在MTP上运行的xUnit.net v3不支持VSTest的
--filter
语法。必须将过滤器转换为xUnit.net v3的原生过滤选项(请参阅步骤5)。

Step 4: Configure dotnet test integration

步骤4:配置dotnet test集成

The
dotnet test
integration depends on the .NET SDK version.
dotnet test
的集成方式取决于.NET SDK版本。

.NET 10 SDK and later (recommended)

.NET 10 SDK及以上版本(推荐)

Use the native MTP mode by adding a
test
section to
global.json
:
json
{
  "sdk": {
    "version": "10.0.100"
  },
  "test": {
    "runner": "Microsoft.Testing.Platform"
  }
}
In this mode,
dotnet test
arguments are passed directly -- for example,
dotnet test --report-trx
.
Important:
global.json
does not support trailing commas. Ensure the JSON is strictly valid.
通过在
global.json
中添加
test
部分使用原生MTP模式:
json
{
  "sdk": {
    "version": "10.0.100"
  },
  "test": {
    "runner": "Microsoft.Testing.Platform"
  }
}
在此模式下,
dotnet test
的参数会直接传递——例如
dotnet test --report-trx
重要提示
global.json
不支持尾随逗号。请确保JSON格式严格有效。

.NET 9 SDK and earlier

.NET 9 SDK及更早版本

Use the VSTest mode of
dotnet test
command to run MTP test projects by adding this property in
Directory.Build.props
:
xml
<PropertyGroup>
  <TestingPlatformDotnetTestSupport>true</TestingPlatformDotnetTestSupport>
</PropertyGroup>
Important: In this mode, you must use
--
to separate
dotnet test
build arguments from MTP arguments. For example:
dotnet test --no-build -- --list-tests
.
通过在
Directory.Build.props
中添加以下属性,使用
dotnet test
命令的VSTest模式运行MTP测试项目:
xml
<PropertyGroup>
  <TestingPlatformDotnetTestSupport>true</TestingPlatformDotnetTestSupport>
</PropertyGroup>
重要提示:在此模式下,必须使用
--
分隔
dotnet test
的构建参数与MTP参数。例如:
dotnet test --no-build -- --list-tests

Step 5: Update dotnet test command-line arguments

步骤5:更新dotnet test命令行参数

VSTest-specific arguments must be translated to MTP equivalents. Build-related arguments (
-c
,
-f
,
--no-build
,
--nologo
,
-v
, etc.) are unchanged.
VSTest argumentMTP equivalentNotes
--test-adapter-path
Not applicableMTP does not use external adapter discovery
--blame
Not applicable
--blame-crash
--crashdump
Requires
Microsoft.Testing.Extensions.CrashDump
NuGet package
--blame-crash-dump-type <TYPE>
--crashdump-type <TYPE>
Requires CrashDump extension
--blame-hang
--hangdump
Requires
Microsoft.Testing.Extensions.HangDump
NuGet package
--blame-hang-dump-type <TYPE>
--hangdump-type <TYPE>
Requires HangDump extension
--blame-hang-timeout <TIMESPAN>
--hangdump-timeout <TIMESPAN>
Requires HangDump extension
--collect "Code Coverage;Format=cobertura"
--coverage --coverage-output-format cobertura
Per-extension arguments
-d|--diag <LOG_FILE>
--diagnostic
--filter <EXPRESSION>
--filter <EXPRESSION>
Same syntax for MSTest, NUnit, and xUnit.net v2 (with
YTest.MTP.XUnit2
). For xUnit.net v3, see filter migration below
-l|--logger trx
--report-trx
Requires
Microsoft.Testing.Extensions.TrxReport
NuGet package
--results-directory <DIR>
--results-directory <DIR>
Same
-s|--settings <FILE>
--settings <FILE>
MSTest and NUnit still support
.runsettings
-t|--list-tests
--list-tests
Same
-- <RunSettings args>
--test-parameter
Applicable only to MSTest and NUnit
VSTest专属的参数必须转换为MTP等效参数。构建相关参数(
-c
-f
--no-build
--nologo
-v
等)保持不变。
VSTest参数MTP等效参数说明
--test-adapter-path
不适用MTP不使用外部适配器发现机制
--blame
不适用
--blame-crash
--crashdump
需要
Microsoft.Testing.Extensions.CrashDump
NuGet包
--blame-crash-dump-type <TYPE>
--crashdump-type <TYPE>
需要CrashDump扩展包
--blame-hang
--hangdump
需要
Microsoft.Testing.Extensions.HangDump
NuGet包
--blame-hang-dump-type <TYPE>
--hangdump-type <TYPE>
需要HangDump扩展包
--blame-hang-timeout <TIMESPAN>
--hangdump-timeout <TIMESPAN>
需要HangDump扩展包
--collect "Code Coverage;Format=cobertura"
--coverage --coverage-output-format cobertura
扩展包专属参数
-d|--diag <LOG_FILE>
--diagnostic
--filter <EXPRESSION>
--filter <EXPRESSION>
MSTest、NUnit和xUnit.net v2(使用
YTest.MTP.XUnit2
)的语法与VSTest一致。对于xUnit.net v3,请参阅下方的过滤器迁移部分
-l|--logger trx
--report-trx
需要
Microsoft.Testing.Extensions.TrxReport
NuGet包
--results-directory <DIR>
--results-directory <DIR>
保持一致
-s|--settings <FILE>
--settings <FILE>
MSTest和NUnit仍支持
.runsettings
文件
-t|--list-tests
--list-tests
保持一致
-- <RunSettings args>
--test-parameter
仅适用于MSTest和NUnit

Filter migration

过滤器迁移

MSTest, NUnit, and xUnit.net v2 (with
YTest.MTP.XUnit2
)
: The VSTest
--filter
syntax is identical on both VSTest and MTP. No changes needed.
xUnit.net v3 (native MTP): xUnit.net v3 does NOT support the VSTest
--filter
syntax on MTP. You must translate filters to xUnit.net v3's native filter options.
MSTest、NUnit和xUnit.net v2(使用
YTest.MTP.XUnit2
:VSTest的
--filter
语法在VSTest和MTP上完全一致,无需修改。
xUnit.net v3(原生MTP):在MTP上运行的xUnit.net v3不支持VSTest的
--filter
语法。必须将过滤器转换为xUnit.net v3的原生过滤选项。

xUnit.net v3 filter flags

xUnit.net v3过滤标志

FlagDescription
--filter-class "name"
Run all tests in a given class. Supports wildcards (
*
).
--filter-not-class "name"
Exclude all tests in a given class
--filter-method "name"
Run a specific test method
--filter-not-method "name"
Exclude a specific test method
--filter-namespace "name"
Run all tests in a namespace
--filter-not-namespace "name"
Exclude all tests in a namespace
--filter-trait "name=value"
Run tests with a matching trait
--filter-not-trait "name=value"
Exclude tests with a matching trait
Multiple values can be specified with a single flag:
--filter-class Foo Bar
.
标志描述
--filter-class "name"
运行指定类中的所有测试。支持通配符(
*
)。
--filter-not-class "name"
排除指定类中的所有测试
--filter-method "name"
运行特定测试方法
--filter-not-method "name"
排除特定测试方法
--filter-namespace "name"
运行指定命名空间中的所有测试
--filter-not-namespace "name"
排除指定命名空间中的所有测试
--filter-trait "name=value"
运行具有匹配特性的测试
--filter-not-trait "name=value"
排除具有匹配特性的测试
单个标志可指定多个值:
--filter-class Foo Bar

VSTest → xUnit.net v3 filter translation table

VSTest → xUnit.net v3过滤器转换对照表

VSTest
--filter
syntax
xUnit.net v3 MTP equivalentNotes
FullyQualifiedName~ClassName
--filter-class *ClassName*
Wildcards required for substring match
FullyQualifiedName=Ns.Class.Method
--filter-method Ns.Class.Method
Exact match on fully qualified method
Name=MethodName
--filter-method *MethodName*
Wildcards for substring match
Category=Value
(trait)
--filter-trait "Category=Value"
Filter by trait name/value pair
Complex expressions
--filter-query "expr"
Uses xUnit.net query filter language (see below)
VSTest
--filter
语法
xUnit.net v3 MTP等效语法说明
FullyQualifiedName~ClassName
--filter-class *ClassName*
子字符串匹配需要使用通配符
FullyQualifiedName=Ns.Class.Method
--filter-method Ns.Class.Method
完全匹配全限定方法名
Name=MethodName
--filter-method *MethodName*
子字符串匹配需要使用通配符
Category=Value
(特性)
--filter-trait "Category=Value"
按特性名称/值对过滤
复杂表达式
--filter-query "expr"
使用xUnit.net查询过滤语言(请参阅下文)

xUnit.net v3 query filter language

xUnit.net v3查询过滤语言

For complex expressions, use
--filter-query
with a path-segment syntax:
text
/<assemblyFilter>/<namespaceFilter>/<classFilter>/<methodFilter>[traitName=traitValue]
Each segment matches against: assembly name, namespace, class name, method name. Use
*
for "match all" in any segment. Documentation: https://xunit.net/docs/query-filter-language
对于复杂表达式,请使用
--filter-query
并采用路径段语法:
text
/<assemblyFilter>/<namespaceFilter>/<classFilter>/<methodFilter>[traitName=traitValue]
每个段分别匹配:程序集名称、命名空间、类名、方法名。任意段均可使用
*
表示“匹配全部”。文档链接:https://xunit.net/docs/query-filter-language

Translation example

转换示例

shell
undefined
shell
undefined

VSTest

VSTest

dotnet test --filter "FullyQualifiedName~IntegrationTests&Category=Smoke"
dotnet test --filter "FullyQualifiedName~IntegrationTests&Category=Smoke"

xUnit.net v3 MTP -- using individual filters (AND behavior)

xUnit.net v3 MTP -- 使用独立过滤器(逻辑与行为)

dotnet test -- --filter-class IntegrationTests --filter-trait "Category=Smoke"
dotnet test -- --filter-class IntegrationTests --filter-trait "Category=Smoke"

xUnit.net v3 MTP -- using query language (assembly/namespace/class/method[trait])

xUnit.net v3 MTP -- 使用查询语言(程序集/命名空间/类/方法[特性])

dotnet test -- --filter-query "///IntegrationTests/*[Category=Smoke]"

> **Note**: When combining `--filter-class` and `--filter-trait`, both conditions must match (AND behavior). For complex expressions, use `--filter-query` with the path-segment syntax. See the [xUnit.net query filter language docs](https://xunit.net/docs/query-filter-language) for full reference.
dotnet test -- --filter-query "///IntegrationTests/*[Category=Smoke]"

> **注意**:组合使用`--filter-class`和`--filter-trait`时,两个条件必须同时满足(逻辑与)。对于复杂表达式,请使用带路径段语法的`--filter-query`。完整参考请查看[xUnit.net查询过滤语言文档](https://xunit.net/docs/query-filter-language)。

Step 6: Install MTP extension packages (if needed)

步骤6:安装MTP扩展包(如有需要)

If CI scripts use TRX reporting, crash dumps, or hang dumps, add the corresponding NuGet packages:
xml
<!-- TRX report generation (replaces --logger trx) -->
<PackageReference Include="Microsoft.Testing.Extensions.TrxReport" Version="1.6.2" />

<!-- Crash dump collection (replaces --blame-crash) -->
<PackageReference Include="Microsoft.Testing.Extensions.CrashDump" Version="1.6.2" />

<!-- Hang dump collection (replaces --blame-hang) -->
<PackageReference Include="Microsoft.Testing.Extensions.HangDump" Version="1.6.2" />

<!-- Code coverage (replaces --collect "Code Coverage") -->
<PackageReference Include="Microsoft.Testing.Extensions.CodeCoverage" Version="17.13.0" />
如果CI脚本使用TRX报告、崩溃转储或挂起转储,请添加对应的NuGet包:
xml
<!-- TRX报告生成(替代--logger trx) -->
<PackageReference Include="Microsoft.Testing.Extensions.TrxReport" Version="1.6.2" />

<!-- 崩溃转储收集(替代--blame-crash) -->
<PackageReference Include="Microsoft.Testing.Extensions.CrashDump" Version="1.6.2" />

<!-- 挂起转储收集(替代--blame-hang) -->
<PackageReference Include="Microsoft.Testing.Extensions.HangDump" Version="1.6.2" />

<!-- 代码覆盖率(替代--collect "Code Coverage") -->
<PackageReference Include="Microsoft.Testing.Extensions.CodeCoverage" Version="17.13.0" />

Step 7: Update CI/CD pipelines

步骤7:更新CI/CD流水线

Azure DevOps

Azure DevOps

If using the VSTest task (
VSTest@3
)
: Replace with the .NET Core CLI task (
DotNetCoreCLI@2
):
yaml
undefined
如果使用VSTest任务(
VSTest@3
:替换为.NET Core CLI任务(
DotNetCoreCLI@2
):
yaml
undefined

Before (VSTest task)

之前(VSTest任务)

  • task: VSTest@3 inputs: testAssemblyVer2: '**/*Tests.dll' runSettingsFile: 'test.runsettings'
  • task: VSTest@3 inputs: testAssemblyVer2: '**/*Tests.dll' runSettingsFile: 'test.runsettings'

After (.NET Core CLI task)

之后(.NET Core CLI任务)

  • task: DotNetCoreCLI@2 displayName: Run tests inputs: command: 'test' arguments: '--no-build --configuration Release'

**If already using DotNetCoreCLI@2**: Update arguments per Step 5 translations. Remember the `--` separator on .NET 9 and earlier:

```yaml
- task: DotNetCoreCLI@2
  displayName: Run tests
  inputs:
    command: 'test'
    arguments: '--no-build -- --report-trx --results-directory $(Agent.TempDirectory)'
  • task: DotNetCoreCLI@2 displayName: Run tests inputs: command: 'test' arguments: '--no-build --configuration Release'

**如果已在使用DotNetCoreCLI@2**:根据步骤5的转换规则更新参数。注意在.NET 9及更早版本中需要使用`--`分隔符:

```yaml
- task: DotNetCoreCLI@2
  displayName: Run tests
  inputs:
    command: 'test'
    arguments: '--no-build -- --report-trx --results-directory $(Agent.TempDirectory)'

GitHub Actions

GitHub Actions

Update
dotnet test
invocations in workflow files with the same argument translations from Step 5.
按照步骤5的参数转换规则,更新工作流文件中的
dotnet test
调用。

Replace vstest.console.exe

替换vstest.console.exe

If any script invokes
vstest.console.exe
directly, replace it with
dotnet test
. The test projects are now executables and can also be run directly.
如果任何脚本直接调用
vstest.console.exe
,请替换为
dotnet test
。测试项目现在已是可执行文件,也可直接运行。

Step 8: Handle behavioral differences

步骤8:处理行为差异

Zero tests exit code

无测试时的退出代码

VSTest silently succeeds when zero tests are discovered. MTP fails with exit code 8. Options:
  • Pass
    --ignore-exit-code 8
    when running tests
  • Add to
    Directory.Build.props
    :
xml
<PropertyGroup>
  <TestingPlatformCommandLineArguments>$(TestingPlatformCommandLineArguments) --ignore-exit-code 8</TestingPlatformCommandLineArguments>
</PropertyGroup>
  • Use environment variable:
    TESTINGPLATFORM_EXITCODE_IGNORE=8
VSTest在未发现任何测试时会静默成功。而MTP会返回退出代码8并失败。解决选项:
  • 运行测试时传递
    --ignore-exit-code 8
    参数
  • Directory.Build.props
    中添加:
xml
<PropertyGroup>
  <TestingPlatformCommandLineArguments>$(TestingPlatformCommandLineArguments) --ignore-exit-code 8</TestingPlatformCommandLineArguments>
</PropertyGroup>
  • 使用环境变量:
    TESTINGPLATFORM_EXITCODE_IGNORE=8

Step 9: Remove VSTest-only packages (optional)

步骤9:移除仅适用于VSTest的包(可选)

Once migration is complete and verified, remove packages that are only needed for VSTest:
  • Microsoft.NET.Test.Sdk
    -- not needed for MTP (MSTest.Sdk v4 already omits it by default)
  • xunit.runner.visualstudio
    -- only needed for VSTest discovery of xUnit.net (not needed when using
    YTest.MTP.XUnit2
    )
  • NUnit3TestAdapter
    VSTest-only features -- the adapter is still needed but only for the MTP runner
Note: If you need to maintain VSTest compatibility during a transition period, keep these packages.
迁移完成并验证通过后,可移除仅用于VSTest的包:
  • Microsoft.NET.Test.Sdk
    ——MTP无需此包(MSTest.Sdk v4默认已不再包含它)
  • xunit.runner.visualstudio
    ——仅在VSTest发现xUnit.net测试时需要(使用
    YTest.MTP.XUnit2
    时无需此包)
  • NUnit3TestAdapter
    的VSTest专属功能——仍需保留适配器,但仅用于MTP运行器
注意:如果在过渡期间需要保持VSTest兼容性,请保留这些包。

Step 10: Verify

步骤10:验证

  1. Run
    dotnet build
    -- confirm zero errors
  2. Run
    dotnet test
    -- confirm all tests pass
  3. Compare test pass/fail counts to the pre-migration baseline
  4. Run the test executable directly (e.g.,
    ./bin/Debug/net8.0/MyTests.exe
    ) -- confirm it works
  5. Verify CI pipeline produces the expected test result artifacts (TRX files, code coverage, crash dumps)
  6. Test that Test Explorer in Visual Studio (17.14+) or VS Code discovers and runs tests
  1. 运行
    dotnet build
    ——确认无错误
  2. 运行
    dotnet test
    ——确认所有测试通过
  3. 将测试通过/失败数量与迁移前的基准值对比
  4. 直接运行测试可执行文件(例如
    ./bin/Debug/net8.0/MyTests.exe
    )——确认可正常工作
  5. 验证CI流水线生成了预期的测试结果工件(TRX文件、代码覆盖率、崩溃转储)
  6. 测试Visual Studio(17.14及以上版本)或VS Code中的测试资源管理器是否可发现并运行测试

Validation

验证清单

  • All test projects use MTP runner (no VSTest-only configuration remains)
  • dotnet build
    completes with zero errors
  • dotnet test
    passes all tests and test counts match pre-migration baseline
  • Test executable runs directly (e.g.,
    ./bin/Debug/net8.0/MyTests.exe
    )
  • CI pipeline produces expected test result artifacts (TRX files, code coverage, crash dumps)
  • Test Explorer in Visual Studio or VS Code discovers and runs tests
  • No
    vstest.console.exe
    invocations remain in CI scripts
  • <OutputType>Exe</OutputType>
    is set for all non-MSTest.Sdk test projects
  • 所有测试项目均使用MTP运行器(无仅适用于VSTest的配置残留)
  • dotnet build
    执行完成且无错误
  • dotnet test
    通过所有测试,且测试数量与迁移前基准值一致
  • 测试可执行文件可直接运行(例如
    ./bin/Debug/net8.0/MyTests.exe
  • CI流水线生成了预期的测试结果工件(TRX文件、代码覆盖率、崩溃转储)
  • Visual Studio或VS Code中的测试资源管理器可发现并运行测试
  • CI脚本中无
    vstest.console.exe
    调用残留
  • 所有非MSTest.Sdk的测试项目均设置了
    <OutputType>Exe</OutputType>

Common Pitfalls

常见陷阱

PitfallSolution
Mixing VSTest and MTP projects in the same solutionMigrate all test projects together -- mixed mode is unsupported
dotnet test
arguments ignored on .NET 9 and earlier
Use
--
to separate build args from MTP args:
dotnet test -- --report-trx
Exit code 8 on CI without failuresMTP fails when zero tests run; use
--ignore-exit-code 8
or fix test discovery
MSTest.Sdk v4 + vstest.console no longer worksMSTest.Sdk v4 no longer adds
Microsoft.NET.Test.Sdk
-- add it explicitly or switch to
dotnet test
Missing
<OutputType>Exe</OutputType>
Required for all setups except MSTest.Sdk (which sets it automatically)
Using
Condition="'$(IsTestProject)' == 'true'"
in
Directory.Build.props
IsTestProject
is not yet defined when
Directory.Build.props
is evaluated -- use
$(MSBuildProjectName.EndsWith('.Tests'))
(or a similar name-based check) instead
陷阱解决方案
同一解决方案中混合VSTest和MTP项目同时迁移所有测试项目——混合模式不受支持
.NET 9及更早版本中
dotnet test
参数被忽略
使用
--
分隔构建参数与MTP参数:
dotnet test -- --report-trx
CI中无失败但返回退出代码8MTP在无测试运行时会失败;使用
--ignore-exit-code 8
或修复测试发现问题
MSTest.Sdk v4 + vstest.console无法正常工作MSTest.Sdk v4不再添加
Microsoft.NET.Test.Sdk
——显式添加该包或切换至
dotnet test
缺少
<OutputType>Exe</OutputType>
除MSTest.Sdk(会自动设置)外,所有配置均需设置此属性
Directory.Build.props
中使用
Condition="'$(IsTestProject)' == 'true'"
IsTestProject
在导入
Directory.Build.props
时尚未定义——改用
$(MSBuildProjectName.EndsWith('.Tests'))
(或类似的基于名称的检查)

Next Steps

后续步骤

  • Use
    run-tests
    for running tests on the new MTP platform
  • Use
    mtp-hot-reload
    for iterative test fixing with hot reload on MTP
  • 使用
    run-tests
    工具在新的MTP平台上运行测试
  • 使用
    mtp-hot-reload
    工具在MTP上通过热重载进行迭代式测试修复

More Info

更多信息