关于 platform-detection
platform-detection 是面向 .NET 测试项目的技能,用于识别实际执行测试的平台及测试框架。它根据项目配置和属性的求值结果判断,避免仅凭单一包或配置文件推断。
主要功能
- 01识别 VSTest 与 MTP 执行平台
- 02识别 MSTest、xUnit、NUnit 和 TUnit
- 03解析 MSBuild 属性及导入顺序
- 04区分测试执行平台与命令模式
- 05检查多目标框架的条件配置
适用场景
- 01排查测试运行平台的判定
- 02确认项目使用的测试框架
- 03诊断测试配置冲突或缺失
- 04比较不同目标框架的测试平台
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ dotnet/ skills --skill platform-detection安装后在 Claude Code 中输入/platform-detection确认已加载。
附带文件references/command-mode.md
详细介绍
测试平台和框架检测
确定项目使用的测试平台(VSTest 或 Microsoft.Testing.Platform)和测试框架(MSTest、xUnit、NUnit、TUnit)。
回复规范
严格遵循用户要求的标签和顺序,并将每个占位符替换为实际分类结果。先给出结论:前面不得添加标题、分析草稿、工具语法或复述模板。接着用一句简洁的证据说明,指出足以证明每项所请求分类的仓库事实。如果请求了 Framework,请写明能识别该框架的包或项目 SDK。仅在存在冲突、配置不完整或不同目标框架配置不同时,才使用第二句话。
Platform 指实际执行测试的平台:VSTest 或 MTP。如果配置冲突或不完整导致无法执行,请报告平台不可用,不要凭空推断平台可成功执行。
绝不能仅根据 global.json 中的 test.runner 对已执行的平台进行分类。
该设置用于选择 dotnet test 命令模式;即使显式设置为 VSTest,也可能桥接到可执行的 MTP 应用。撰写 Platform: 前,还要检查项目运行器、桥接设置和输出形态等信号。
撰写证据前,先应用以下范围规则:
| 用户要求 | 应包含的证据 | 应省略 |
|---|---|---|
| 平台和框架 | 最终运行器选择器及其生效来源;用于识别框架的包或项目 SDK;必要时,说明使其可执行的属性 | 命令模式;常见 SDK 事实;除非缺失或存在冲突,否则不提 OutputType |
| 唯一决定性信号 | 该运行器选择属性、其来源为何生效,以及竞争包为何不会选择或暗示 VSTest;如用户还要求框架,则仍须写明用于识别框架的包或项目 SDK | 配置完整时,省略桥接、OutputType、SDK 模式及无关前提 |
| 各目标框架对应的平台 | 仅列出存在差异的条件最终值 | 共同属性和项目级 SDK 说明 |
| 显式选择退出 | 最终的 UseVSTest 值及其生效来源 | 已被取代的默认值,除非它们造成冲突 |
dotnet test 模式 | 分别说明命令模式和实际执行平台 | 不省略任何所请求的类别 |
如果用户要求的标签中不包含 dotnet test mode,则回复中不得提及或解释命令模式。精确的桥接属性仍可作为决定性平台证据,但不要将其延伸为 SDK 或 CLI 模式说明。
如果用户询问在显式运行器属性和 Microsoft.NET.Test.Sdk 之间,哪个单一信号起决定作用,证据句必须同时说明:运行器属性选择了 MTP,且 Microsoft.NET.Test.Sdk 不会选择或暗示 VSTest。
如果某项属性由导入优先级决定,请说明生效来源为何优先(例如,它导入得更晚,或其条件适用),而不只是说它包含最终值或覆盖了其他赋值。
说明应围绕用户要求的类别展开:
global.json中的 SDK 版本固定值属于背景信息,不是平台选择器。只有当global.json的test.runner设置确实作出选择时,才能说它选择了 VSTest 或原生 MTP。- 如果决定性设置为
UseVSTest=true,请直接说明。不要臆测未出现的test.runner,也不要把 SDK 版本固定描述为另一项平台选择。 - 如果用户未询问命令模式,即使内部判断已执行平台时用到了它,也不要在回复中添加命令模式。
- 如果有关传统项目的请求还询问命令系列,请直接写一行,例如
Command family: MSBuild + vstest.console.exe;不要将其说成可选方案,也不要添加不必要的构建限定说明。 对于基于文件的请求,请先列出以下配置名称,然后通过一次批量操作读取所有相关且存在的文件:global.json、.csproj、packages.config、Directory.Build.props、Directory.Build.targets、Directory.Packages.props,以及显式导入的.props/.targets。项目文件中缺少的设置可能由导入文件定义,因此切勿仅凭.csproj推断其最终值。如果仓库配置已足够,请勿搜索网络或检查无关文件。
应按照实际的 MSBuild 导入顺序解析属性,而不是采用固定的“项目文件优先于 props”规则。对于每个适用的目标框架:
- 遵循导入关系图和条件。最后一个适用的赋值生效。
Directory.Build.props通常在项目主体之前导入,因此,无条件的项目赋值通常会覆盖它;后续的.targets则可能再次覆盖项目中的赋值。 - 记录
UseVSTest、框架运行器选择器、TestingPlatformDotnetTestSupport和OutputType的最终值及其生效来源。 - 将
Directory.Packages.props视为版本依据,除非其中也包含相关属性。应用依赖版本的默认值之前,先解析程序包/SDK 版本。 - 切勿根据程序包是否存在来推断属性。只有当已解析的版本确实提供该属性,且后续没有赋值覆盖时,程序包或 SDK 默认值才有效。
检测项目系统
选择 CLI 之前,先对项目进行分类:
- 根级
Sdk属性或<Sdk>声明:SDK 风格。 ToolsVersion、Microsoft.Common.props/Microsoft.CSharp.targets导入、 显式的<Reference>和<Compile Include>项:经典非 SDK 风格。packages.config:经典 NuGet 依赖管理。
经典项目仍可使用与 VSTest 兼容的适配器,但 dotnet test 并非自动适用的调用方式。保留仓库中的脚本/CI 命令,通常是先运行 MSBuild,再运行 vstest.console.exe。只有在仓库配置或文档明确说明使用旧版运行器时,才提及 MSTest.exe。
检测测试框架
读取 .csproj、相邻的 packages.config 和
Directory.Build.props / Directory.Packages.props,并查找以下内容:
| 程序包或 SDK 引用 | 框架 |
|---|---|
MSTest 元程序包、<Project Sdk="MSTest.Sdk[/version]"> 或 <Sdk Name="MSTest.Sdk"> | MSTest |
MSTest.TestFramework + MSTest.TestAdapter | MSTest(v3/v4 也适用) |
xunit、xunit.v3、xunit.v3.mtp-v1、xunit.v3.mtp-v2、xunit.v3.core.mtp-v1、xunit.v3.core.mtp-v2 | xUnit |
NUnit + NUnit3TestAdapter | NUnit |
TUnit | TUnit(仅限 MTP) |
在经典项目中,程序包 ID 和版本可能只出现在
packages.config 中,而项目文件则包含带 HintPath 值的程序集 <Reference> 元素。请同时使用这两类来源。
检测实际执行的测试平台
如果用户明确要求使用 dotnet test 模式,请在回答前读取
references/command-mode.md。
对于仅询问平台/框架的请求,不要加载该参考文件,也不要提及命令模式。
对于 SDK 8/9 的请求,如果明确询问命令模式且没有有效桥接,请用一个体现因果关系的句子说明以下三点:运行器使项目具备 MTP 能力,dotnet test 仍处于 VSTest 模式,而缺少桥接意味着实际执行测试的是 VSTest。只有在有助于解释结果时,才提及原生 MTP 命令模式从 SDK 10 开始支持。
允许执行,且提示和 global.json 均未指定 SDK 时,运行一次 dotnet --version。对于禁止执行的只读识别请求,不要探测已安装的 SDK;应依据仓库事实,并说明任何必要的 SDK 假设。
解析出最终属性值后,按以下顺序分类:
- 最终的
UseVSTest=true会选择 VSTest。如果global.json同时选择了原生 MTP 命令模式,则应报告Platform: unavailable,因为命令模式与项目选择退出相冲突。 - 在
global.json中选择原生 MTP 后,最终OutputType=Exe的兼容 MTP 应用会在 MTP 上执行。仅支持 VSTest、输出类型为库或选择退出的项目不可用。 - 在 SDK 8/9 上,启用 MTP 运行器、最终
TestingPlatformDotnetTestSupport=true且最终OutputType=Exe时,会在 MTP 上执行。 - 如果运行器已启用,但缺少桥接或桥接值为 false,支持双模式的 MSTest、NUnit 或 xUnit 项目仍会使用 VSTest:运行器表明具备 MTP 能力,但 SDK 8/9 的
dotnet test无法访问它,因此由 VSTest 适配器执行测试。如果桥接值为 true,但未启用任何运行器,项目也仍会使用 VSTest。 - 运行器和桥接均已启用,但输出类型不可执行,说明配置不完整,项目不可用。如果选定的 SDK 路径无法访问仅支持 MTP 的框架,该项目同样不可用,而不是使用 VSTest。
每个信号的作用必须准确:
- 运行器属性用于选择测试应用。
TestingPlatformDotnetTestSupport=true使 SDK 8/9 的dotnet test能够访问该应用。OutputType=Exe提供可执行文件的宿主形式。它不会选择或启用 MTP。
不要混淆 MSTest 元包与 MSTest.Sdk 项目 SDK。
PackageReference Include="MSTest" 加上 EnableMSTestRunner=true 会启用 MSTest MTP 运行器,但不会隐式设置 TestingPlatformDotnetTestSupport。
MSTest.Sdk 默认会启用 MTP 运行器。请检查其解析后的版本和求值后的属性,以确认桥接行为:版本 3.8 会提供 TestingPlatformDotnetTestSupport,除非后续赋值覆盖它;而在 .NET 10 上,较新的 SDK 可能会改为预期使用原生 MTP 模式。
<UseVSTest>true</UseVSTest> 会选择返回 VSTest。
| 信号 | 含义 |
|---|---|
<Project Sdk="MSTest.Sdk..."> 且没有 UseVSTest | MTP 应用;检查解析后的 SDK 版本和求值后的桥接属性 |
MSTest 元包 + <EnableMSTestRunner>true> | 已启用 MTP 运行器;不代表存在 VSTest 到 MTP 的桥接 |
<UseMicrosoftTestingPlatformRunner>true | 用于选择 xUnit 运行器的决定性信号 |
<EnableMSTestRunner>true> / <EnableNUnitRunner>true> | 用于选择 MSTest/NUnit 运行器的决定性信号 |
TestingPlatformDotnetTestSupport=true | VSTest 到 MTP 桥接的执行前提条件,而不是运行器选择信号 |
Microsoft.Testing.Platform 包 | 支持 MTP 的应用;单独看它无法作出决定 |
TUnit | 仅支持 MTP 的框架 |
最终求值结果为 <OutputType>Exe</OutputType> | 基于包的 MTP 应用所需的可执行文件宿主形式 |
仅有 Microsoft.NET.Test.Sdk 并不足以作出决定;在启用了 MTP 的项目中,它可以出于兼容性目的继续保留。如果明确的覆盖设置决定了结果,请指出最终覆盖设置及其来源,而不是被覆盖的默认值。
当运行器选择属性与 Microsoft.NET.Test.Sdk 相互竞争时,应说明运行器属性选择了 MTP,而 Microsoft.NET.Test.Sdk 不会选择或暗示 VSTest。它可以作为兼容性支持保留,但只是次要因素。TestingPlatformDotnetTestSupport=true 是桥接的前提条件,而不是运行器选择信号;切勿说仅靠此属性就能启用桥接。如果用户询问哪个单一信号起决定作用,请到此为止。配置完整时,省略桥接或宿主形式的前提条件;仅在需要解释所选运行器为何无法执行时,才补充这些条件。
同样,如果启用的运行器被覆盖或无法访问,应从因果关系上说明这两个方面:运行器属性使项目具备 MTP 能力,但最终的 UseVSTest/桥接/输出设置决定实际执行的平台。先指出运行器选择器,再使用包引用仅用于识别框架。
使用因果证据,而不是堆砌信号。例如:
Platform: MTP
Framework: NUnit
Directory.Build.props supplies final EnableNUnitRunner=true and
TestingPlatformDotnetTestSupport=true, so NUnit executes on MTP.
如果配置不兼容,请在给出判定后提供一种最简对齐方案,不修改文件:要么全局选择项目已配置的平台,要么移除项目级退出设置,以使用全局选定的平台。
条件属性和按目标框架设置的属性
针对每个目标框架评估运行器和桥接属性。如果条件导致实际执行的平台不同,请明确报告每个目标(例如,net8.0: VSTest、net9.0: MTP),不要将整个项目归为同一个全局平台。