mcpField
M
migrate-xunit-to-xunit-v3

migrate-xunit-to-xunit-v3

github.com/dotnet测试与质量5.8k3.4k 次安装1 天前更新
代码仓库

关于 migrate-xunit-to-xunit-v3

用于将 .NET 测试项目从 xUnit.net v2 迁移到 v3 的技能,面向维护现有 xUnit 测试套件的开发者。它涵盖包与运行器配置调整,以及受影响源码的迁移和测试验证。

主要功能

  1. 01迁移 xUnit.net 包引用
  2. 02保留原有测试平台
  3. 03检查并修复 v3 API 变更
  4. 04执行测试并核实结果

适用场景

  1. 01升级测试项目至 xUnit.net v3
  2. 02修复切换 v3 后的编译错误

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dotnet/skills --skill migrate-xunit-to-xunit-v3

安装后在 Claude Code 中输入/migrate-xunit-to-xunit-v3确认已加载。

详细介绍

xunit.v3 迁移

将 .NET 测试项目从 xUnit.net v2 迁移到 xUnit.net v3。最终结果应是:所有测试项目都引用 xunit.v3.* 包,能够顺利编译,并且所有测试通过且结果与迁移前一致。

适用场景

  • 将测试项目从 xunit(v2)包升级到 xunit.v3
  • 更新 xunit 包引用到 v3 后,解决编译错误

不适用场景

  • 在不同测试框架之间迁移(例如从 MSTest 或 NUnit 迁移到 xUnit.net)——这是完全不同的工作
  • 从 VSTest 迁移到 Microsoft.Testing.Platform——请使用 migrate-vstest-to-mtp
  • 项目已经引用 xunit.v3——迁移已完成

输入

输入必需描述
测试项目或解决方案否在当前工作目录中查找 .csproj、.sln、.slnx、central props 和源代码;仅在未找到任何内容或目标不明确时询问

工作区与完成要求

  • 激活技能不代表任务已完成。对于迁移/修复/更新请求,应检查暂存文件、编辑这些文件,并在同一任务中运行测试。
  • 技能基础目录仅包含指导内容。搜索当前工作目录,并按返回的路径原样打开文件。
  • 如果工具拒绝已搜索到的路径,应先判断拒绝原因。只有在明确确认是读取器/路径规范化限制,且访问已获授权时,才允许通过其他获准的读取器/编辑器重试。
  • 遇到权限、策略或内容排除导致的拒绝时,应停止访问该路径并报告阻碍。切勿通过其他工具、shell 命令、别名或 Agent 绕过拒绝,也不得推断或重建受限内容。
  • 如果拒绝原因不明确,应将该路径视为不可用,而非不存在。仅继续进行其他独立获准的工作,并明确说明迁移未完成。
  • 只要仍可通过工作区发现文件,就不要要求用户提供路径。
  • 一次性盘点项目/中央包文件以及所有受影响的源代码。如果仍存在仅适用于 v2 的 API,则仅迁移包并不完整。
  • 结束时说明检测到的源版本和运行器、精确的包兼容组合、已更改文件、已发现/通过/失败/跳过的数量,以及任何特定于平台的结果。未发现测试的构建不算成功。
  • 包是否有效需以实际验证为准:记录已配置的源查询或已解析的包依赖关系图,并确认还原成功。在最终结果中说明如何验证所选精确版本确实可用;不要只给出版本号并让评审者或用户自行判断其是否存在。

工作流程

提交策略: 除非用户提出要求,否则不要创建提交。确保项目配置和源代码编辑在差异中逻辑上可分,但要完成并验证整个迁移请求。

优先级: 每次迁移都必须执行步骤 1–5。步骤 6–12 为条件步骤——仅在与项目代码模式相关时应用。跳过不适用的步骤。

会改变结果的决策

编辑前运行此预检:

检测到的状态必需操作
项目引用 xunit.v3,具有必需的可执行文件/运行器配置,不再包含 v2 包或仅适用于 v2 的 API 模式,且现有测试命令通过停止:迁移已完成。不要更新版本、创建 props 文件或修改源代码。报告已验证的无操作结果。如果仍需进行任何必需的 v3 适配,只做该项修复,不要仅凭包引用就视为迁移完成。
xUnit v2 使用 YTest.MTP.XUnit2保留 MTP:移除此 shim,设置 UseMicrosoftTestingPlatformRunner=true,不要添加 xunit.runner.visualstudio 或 IsTestingPlatformApplication=false。
xUnit v2 未使用 MTP shim保留 VSTest:保留/更新 xunit.runner.visualstudio,并设置 IsTestingPlatformApplication=false。
自定义类型派生自 BeforeAfterTestAttribute保留此继承关系及其行为。为两个重写方法都添加 IXunitTest 参数,并将其传递给 base.Before/base.After;不要将子类替换为直接实现接口。
基于类型的集合/排序器属性指向自定义类型迁移属性语法和所引用类型的 v3 契约。对于集合工厂,实现 xUnit v3 所要求的 IXunitTestCollectionFactory 行为;仅编译该属性但保留空工厂,不算完成迁移。
存在配套包从已配置的源中,将 xunit.v3、Xunit.Combinatorial 和 Xunit.StaFact 解析为兼容的一组版本。如果这些源中最新的 xunit.v3 主版本没有兼容的稳定版配套包,则选择最新的兼容 xunit.v3 主版本,并说明固定版本的原因。验证测试发现,而不仅仅是编译。
OutputType=Exe 导致 net*-windows 项目在非 Windows 主机上失败如果计划进行跨平台构建,则添加 EnableWindowsTargeting=true,然后重新运行。不要将此迁移引起的失败视为原有问题而忽略。

从已配置的包源解析包版本。不要根据产品名称中的“v3”猜测版本,也不要更新无关的包。只修改包含适用规则所要求的包、属性或源代码结构的文件。

编辑中央包管理项目后,重新读取 Directory.Packages.props 和项目文件。确认版本由 PackageVersion 管理,重命名后的 PackageReference 不包含版本,并且 OutputType=Exe 已生效。

步骤 1:识别 xUnit.net 项目并验证兼容性

搜索引用 xUnit.net v2 包的测试项目:

  • xunit
  • xunit.abstractions
  • xunit.assert
  • xunit.core
  • xunit.extensibility.core
  • xunit.extensibility.execution
  • xunit.runner.visualstudio

务必检查项目文件、MSBuild props 和 targets 文件(例如 Directory.Build.props、Directory.Build.targets 和 Directory.Packages.props)中的包引用。

验证目标框架兼容性:xUnit.net v3 要求 .NET 8+ 或 .NET Framework 4.7.2+。对于测试库项目,也支持 .NET Standard 2.0。如果任何测试项目的目标框架不兼容,请在此处停止,并告知用户先升级目标框架。同时验证项目使用的是 SDK 样式格式。

步骤 2:更新包引用
  1. 根据以下映射,将 PackageReference 或 PackageVersion 项更新为新的包名称:

    • xunit → xunit.v3
    • xunit.abstractions → 完全移除
    • xunit.assert → xunit.v3.assert
    • xunit.core → xunit.v3.core
    • xunit.extensibility.core 和 xunit.extensibility.execution → xunit.v3.extensibility.core(如果项目同时引用这两个包,请合并为单个条目,因为这两个包已合并)
  2. 查询已配置的包源,并固定为实际存在的最新稳定版本。仅对 VSTest 项目更新 xunit.runner.visualstudio;不要将其添加到 MTP 项目。

步骤 3:将 OutputType 设为 Exe

在每个测试项目(测试库项目除外)中,于项目文件内将 OutputType 设为 Exe:

<PropertyGroup>
  <OutputType>Exe</OutputType>
</PropertyGroup>

根据当前解决方案的情况,可以在集中位置添加此设置。例如:

  • 如果所有测试项目都共用(或可以共用)一个 Directory.Build.props,请在其中添加 <OutputType>Exe</OutputType> 属性。请注意,不应将 OutputType 添加到 Directory.Build.targets。
  • 如果所有测试项目都遵循相同的名称模式(例如 *.Tests.csproj),请在 Directory.Build.props 中添加一个条件属性组,使其仅应用于这些项目,例如 <OutputType Condition="$(MSBuildProjectName.EndsWith('.Tests'))">Exe</OutputType>。请根据需要调整条件,确保只针对测试项目。
  • 否则,请分别将 <OutputType>Exe</OutputType> 属性添加到每个测试项目文件中。
步骤 4:配置测试平台

保留 xUnit.net v2 所使用的测试平台。xUnit.net v2 始终使用 VSTest,除非项目使用了 YTest.MTP.XUnit2。

  • 如果项目引用了 YTest.MTP.XUnit2:
    • 完全移除对 YTest.MTP.XUnit2 的引用。
    • 在现有的共享 Directory.Build.props 中,或在没有共享 props 文件时于测试项目中,设置 <UseMicrosoftTestingPlatformRunner>true</UseMicrosoftTestingPlatformRunner>。
    • 不要添加 xunit.runner.visualstudio;它是 VSTest 运行器,会削弱对原有平台的保留。
  • 如果项目未引用 YTest.MTP.XUnit2(常见情况):
    • 在现有的共享 Directory.Build.props 中,或在没有共享 props 文件时直接在测试项目中,设置 <IsTestingPlatformApplication>false</IsTestingPlatformApplication>。不要仅为一个项目创建仓库级 props 文件。这样可以让项目继续使用 VSTest。
步骤 5:移除 Xunit.Abstractions using 指令

查找 C# 文件中的所有 using Xunit.Abstractions; 指令,并将其完全移除。

步骤 6:处理 async void 破坏性变更(如适用)

在 xUnit.net v3 中,不再支持 async void 测试方法,并且这类方法会导致编译失败。搜索所有声明为 async void 的测试方法,并将其改为 async Task。可通过 [Fact]、[Theory] 或其他测试特性识别测试方法。

在最终结果中,说明源代码更改的原因:xUnit.net v3 不接受 async void 测试,因此每个受影响的方法现在都返回 Task。不要只报告机械性的替换。还要说明如何从已配置的源解析出确切的包版本。

步骤 7:处理特性的破坏性变更(如适用)

在 xUnit.net v3 中,某些特性已更新为接受 System.Type,而不是两个字符串(完全限定类型名称和程序集名称)。这些特性包括:

  • CollectionBehaviorAttribute
  • TestCaseOrdererAttribute
  • TestCollectionOrdererAttribute
  • TestFrameworkAttribute

例如,[assembly: CollectionBehavior("MyNamespace.MyCollectionFactory", "MyAssembly")] 必须改为 [assembly: CollectionBehavior(typeof(MyNamespace.MyCollectionFactory))]。

步骤 8:继承自 FactAttribute 或 TheoryAttribute(如适用)

确认是否有任何自定义特性继承自 FactAttribute 或 TheoryAttribute。这些自定义用户定义特性现在必须提供源信息。例如,如果特性原本如下所示:

internal sealed class MyFactAttribute : FactAttribute
{
    public MyFactAttribute()
    {
    }
}

则必须将其改为:

internal sealed class MyFactAttribute : FactAttribute
{
    public MyFactAttribute(
        [CallerFilePath] string? sourceFilePath = null,
        [CallerLineNumber] int sourceLineNumber = -1
    ) : base(sourceFilePath, sourceLineNumber)
    {
    }
}

报告完成前,请逐一复核所有受影响的 FactAttribute 和 TheoryAttribute 派生构造函数。列出每种类型,并确认调用方信息参数和对应的 base(sourceFilePath, sourceLineNumber) 转发都已存在。测试通过本身并不能证明源信息已正确传递。

步骤 9:继承自 BeforeAfterTestAttribute(如适用)

确认是否有任何自定义特性继承自 BeforeAfterTestAttribute。这些自定义用户定义特性必须更新其方法签名。此前,它们的 Before/After 重写方法可能如下所示:

    public override void Before(MethodInfo methodUnderTest)
    {
        // Possibly some custom logic here
        base.Before(methodUnderTest);
        // Possibly some custom logic here
    }

    public override void After(MethodInfo methodUnderTest)
    {
        // Possibly some custom logic here
        base.After(methodUnderTest);
        // Possibly some custom logic here
    }

则必须将其改为:

    public override void Before(MethodInfo methodUnderTest, IXunitTest test)
    {
        // Possibly some custom logic here
        base.Before(methodUnderTest, test);
        // Possibly some custom logic here
    }

    public override void After(MethodInfo methodUnderTest, IXunitTest test)
    {
        // Possibly some custom logic here
        base.After(methodUnderTest, test);
        // Possibly some custom logic here
    }

保留 BeforeAfterTestAttribute 基类和重写修饰符,并保留现有的基类调用及其相对于自定义逻辑的顺序。直接实现 IBeforeAfterTestAttribute 可能可以编译,但这并非从 v2 到 v3 的机械式迁移,而且可能丢弃基类行为。

报告完成前,请阅读最终的特性文件,并引用实际的 Before(MethodInfo, IXunitTest) 和 After(MethodInfo, IXunitTest) 签名。明确确认 base.Before 和 base.After 接收的是同一个 IXunitTest 参数;仅笼统声称已更新重写方法不足以作为证据。

步骤 10:处理新的 xUnit 分析器警告(如适用)

xunit.v3 引入了新的分析器警告。最值得注意的是 xUnit1051(对于接受 CancellationToken 的方法,使用 TestContext.Current.CancellationToken)。如果存在这类警告,请予以处理。

步骤 11:迁移 Xunit.SkippableFact(如适用)

如果存在对 Xunit.SkippableFact 的包引用,请将这些包引用全部移除。

然后,按照以下步骤消除对已移除包所提供 API 的使用:

  • 将所有 SkippableFact 特性替换为常规的 Fact 特性。
  • 将所有 SkippableTheory 特性替换为常规的 Theory 特性。
  • 将 Skip.If 方法调用改为 Assert.SkipWhen。
  • 将 Skip.IfNot 方法调用改为 Assert.SkipUnless。

如果测试夹具允许,请验证两个分支:默认条件应报告预期的跳过原因,启用条件则应执行并通过。仅进行 grep 检查和笼统地运行测试并通过,无法证明运行时跳过语义得到了保留。

此转换仅限于现有项目文件/集中式包文件,以及包含这些 API 的源文件。不要仅为迁移此配套包而新建 Directory.Build.props;如果不存在共享 props 文件,任何必需的运行器属性都应放在现有测试项目中。

步骤 12:更新配套包(如适用)
  • 查询已配置的软件源,获取一组相互兼容的版本,而不是分别解析每个包。Xunit.Combinatorial 1.x 应升级到 2.x 或更高版本,而 Xunit.StaFact 1.x 应升级到与所选 xunit.v3 主版本兼容的版本系列。
  • 不要根据产品名称或匹配的主版本号推断配套包是否兼容。请使用包依赖约束和已配置软件源中可用的版本,并通过测试发现来证明所选版本组合可行。
  • 在 Linux/macOS 上构建 net*-windows 项目并切换到可执行输出时,如果有意进行跨目标构建,请设置 EnableWindowsTargeting=true。
  • 运行测试,并将预期的平台跳过(例如 Linux 上的 STA 测试)与失败分别确认。
步骤 13:构建并验证

构建解决方案并修复所有剩余的编译错误。运行 dotnet test,确认所有测试均通过,且结果与迁移前相同。

评论

支持 Markdown