Skip to main content

migrate-xunit-to-mstest

Migrate .NET test projects from xUnit.net (v2 or v3) to MSTest v4. USE FOR: convert/migrate xUnit tests to MSTest, replace xunit/xunit.v3 packages, port [Fact]/[Theory]/[InlineData]/[MemberData]/[ClassData] to [TestMethod]/[DataRow]/[DynamicData], port Assert.Equal/True/Throws/ThrowsAsync to Assert.AreEqual/IsTrue/ThrowsExactly/ThrowsExactlyAsync, port IClassFixture/ ICollectionFixture/IDisposable/IAsyncLifetime/ITestOutputHelper/[Trait]/[Fact(Skip)] to MSTest equivalents, preserve xUnit parallel-class default via [assembly: Parallelize(Scope = ClassLevel)], remove xunit.runner.json. DO NOT USE FOR: xUnit v2 -> v3 upgrade (use migrate-xunit-to-xunit-v3); MSTest -> xUnit, NUnit/TUnit -> MSTest (no skills exist); MSTest version upgrades (use migrate-mstest-v1v2-to-v3 or migrate-mstest-v3-to-v4); VSTest <-> MTP only (use migrate-vstest-to-mtp); general .NET upgrades.

Informações da origem

Repositório
dotnet/sdk
Última atividade na origem
3 de setembro de 2026 às 11:14
Idioma detectado do SKILL.md
inglês
Estrelas
3.227
Forks
1.300

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Explorador de arquivos
2 arquivos

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
migrate-xunit-to-mstest
description
Migrate .NET test projects from xUnit.net (v2 or v3) to MSTest v4. USE FOR: convert/migrate xUnit tests to MSTest, replace xunit/xunit.v3 packages, port [Fact]/[Theory]/[InlineData]/[MemberData]/[ClassData] to [TestMethod]/[DataRow]/[DynamicData], port Assert.Equal/True/Throws/ThrowsAsync to Assert.AreEqual/IsTrue/ThrowsExactly/ThrowsExactlyAsync, port IClassFixture/ ICollectionFixture/IDisposable/IAsyncLifetime/ITestOutputHelper/[Trait]/[Fact(Skip)] to MSTest equivalents, preserve xUnit parallel-class default via [assembly: Parallelize(Scope = ClassLevel)], remove xunit.runner.json. DO NOT USE FOR: xUnit v2 -> v3 upgrade (use migrate-xunit-to-xunit-v3); MSTest -> xUnit, NUnit/TUnit -> MSTest (no skills exist); MSTest version upgrades (use migrate-mstest-v1v2-to-v3 or migrate-mstest-v3-to-v4); VSTest <-> MTP only (use migrate-vstest-to-mtp); general .NET upgrades.
license
MIT
# xUnit -> MSTest Migration Migrate a .NET test project from xUnit.net (v2 or v3) to MSTest v4. The outcome is a project that: - References MSTest v4 packages (or `MSTest.Sdk` 4.x) instead of `xunit*` / `xunit.v3.*` - Has every `[Fact]`/`[Theory]` rewritten as `[TestMethod]` and every assertion mapped to the MSTest equivalent - Builds cleanly with the same target framework - Passes the same set of tests (modulo intentional changes documented below) - Preserves the **current test platform** (VSTest stays on VSTest; MTP stays on MTP) This is a **cross-framework** migration. Do not bundle it with a version upgrade or a platform switch in the same pass -- if both are needed, do this skill first, commit, then run `migrate-mstest-v3-to-v4` (if you stopped on v3) or `migrate-vstest-to-mtp`. ## When to Use - The project references `xunit`, `xunit.assert`, `xunit.core`, `xunit.extensibility.core`/`execution`, `xunit.abstractions`, or any `xunit.v3.*` package, and you want to switch to MSTest - You want a single .NET test framework across a solution that today mixes xUnit and MSTest ## Inputs | Input | Required | Description | |-------|----------|-------------| | Project or solution path | Yes | The `.csproj`, `.sln`, or `.slnx` containing xUnit test projects | | Build command | No | How to build (e.g., `dotnet build`). Auto-detect if not provided | | Test command | No | How to run tests (e.g., `dotnet test`). Auto-detect if not provided | ## Response Guidelines - **Always identify the current xUnit version first.** State whether the project is on xUnit v2 (`xunit` 2.x) or xUnit v3 (`xunit.v3` / `xunit.v3.*`) before recommending changes. This grounds the migration advice -- some breaking-change steps only apply to one version. - **Always preserve the current test platform.** If the project runs on VSTest, keep VSTest. If it runs on MTP (e.g., xUnit v3 native MTP, or `<UseMicrosoftTestingPlatformRunner>true</UseMicrosoftTestingPlatformRunner>`), keep MTP. Recommend `migrate-vstest-to-mtp` as a separate follow-up only if the user asks for it. - **Explicitly communicate every judgement-call decision** before applying it -- otherwise the user cannot tell what changed semantically. In particular: - **Fixture scope changes** (Step 8): state the source scope (class / collection / assembly) and the target scope you chose, plus what gets shared and what gets serialized. A silent widening from collection to assembly is the most common way this migration regresses tests. - **Parallelization** (Step 11): state that **MSTest defaults to serial execution** (xUnit parallelizes classes by default), so an explicit `[assembly: Parallelize(...)]` is **required** to match xUnit's behaviour -- omitting it silently halves CI throughput. - **`Assert.Throws<T>` -> `Assert.ThrowsExactly<T>`** (Step 6): mention the exact-type-vs-any-derived semantic flip so reviewers know the assertion was deliberately renamed, not just translated. - **Specific API mapping questions** (assertions, fixtures, output helper, etc.): jump to the relevant step. Do not run the full workflow. - **Full migration requests**: follow the workflow end-to-end. - **Focused fix requests** (specific compile error after a partial migration): address only that error using the mapping reference. Do not walk the full workflow. - **Code samples**: show concrete before/after using the user's actual type/method names, not generic placeholders. ## Strategy The conversion is mechanical for ~80% of code (attributes and simple assertions) and judgement-based for ~20% (collection fixtures, custom data attributes, exact-type-vs-derived exception assertions, parallelization semantics). Always do the mechanical pass first so build errors point you at the judgement areas. ## Mapping Reference For the full attribute/assertion/fixture/lifecycle mapping tables -- including semantic traps (`Assert.Throws<T>` vs `Assert.ThrowsAny<T>`, `IClassFixture` vs `ICollectionFixture` scope), edge cases (`TheoryData<T...>`, `MemberType=`, custom `DataAttribute`, custom `FactAttribute`, `Record.Exception`), and copy-pasteable before/after snippets -- see [`references/mapping-cheatsheet.md`](references/mapping-cheatsheet.md). Load it whenever you need a specific xUnit -> MSTest equivalent. For writing idiomatic MSTest code (modern assertion APIs, lifecycle patterns, data-driven conventions, `Assert.HasCount`/`IsEmpty`/`StartsWith`, etc.), see the `writing-mstest-tests` skill. **Do not re-derive idiomatic MSTest patterns here.** Apply this skill to *convert*; apply `writing-mstest-tests` to *polish*. ## Workflow > **Commit strategy:** Commit after Step 2 (packages updated, builds broken), after Step 6 (attributes converted, asserts fixed), and after Step 8 (fixtures/lifecycle rewritten, tests pass). Commit before fixing follow-up cleanup so reviewers can bisect. ### Step 1: Assess the project 1. Locate every test project. Read `.csproj`, `Directory.Build.props`, `Directory.Packages.props`, and `global.json`. 2. Identify the **xUnit version**: - `xunit` 2.x (+ `xunit.assert` / `xunit.core` / `xunit.abstractions`) -> **xUnit v2** - `xunit.v3` / `xunit.v3.*` -> **xUnit v3** 3. Identify the **current test platform** (this dictates what to keep, not what to change) by invoking the `platform-detection` skill. The xUnit/MTP matrix is nuanced -- xunit.v3 inside Test Explorer is MTP by default unless opted out, while xunit.v3 inside `dotnet test` depends on the `xunit.v3.mtp-v*` packages -- so do not try to inline a shortcut here. Quick signals to feed into that skill: `xunit.runner.visualstudio` (v2) usually means VSTest; `xunit.v3.mtp-v*` / `xunit.v3.core.mtp-v*` packages or `YTest.MTP.XUnit2` (v2 MTP shim) usually mean MTP. `<UseMicrosoftTestingPlatformRunner>` only affects `dotnet run` and is **not** a reliable VSTest-vs-MTP signal on its own. 4. Verify the `TargetFramework` is supported by MSTest v4: - **Supported**: `net8.0`, `net9.0`, `net462`+, `netstandard2.0` (test library only), `uap10.0.16299`, `net8.0-windows10.0.18362.0` (WinUI), `net9.0-windows10.0.17763.0` (modern UWP). - **Unsupported**: .NET Core 3.1, `net5.0`-`net7.0`. **STOP** and ask the user to upgrade the TFM first, or migrate to MSTest v3 (then use `migrate-mstest-v3-to-v4` after a TFM bump). 5. Inventory high-risk patterns -- scan for these and flag them now so you can plan judgement steps later: - **Parallelization differences (Step 11)** -- xUnit parallelizes test classes by default; MSTest does not. This is the **single most common source of post-migration regressions**: tests that depended on isolation by parallel scheduling, on the lack of it, or on shared static state can pass differently. Decide the target parallelization model now -- do not leave it as the MSTest default by accident. - `ICollectionFixture<T>` / `[CollectionDefinition]` (scope concern -- see Step 8) - Custom `DataAttribute` / custom `FactAttribute` / custom `TheoryAttribute` subclasses (manual conversion to `ITestDataSource` / `TestMethodAttribute` -- see Step 5) - `Assert.Throws<T>` (xUnit semantics = exact type; maps to `Assert.ThrowsExactly<T>`, **not** `Assert.Throws<T>`) - `Record.Exception` / `Record.ExceptionAsync` (manual conversion) - `Assert.Raises*` / event assertions (no MSTest equivalent -- manual) - xUnit v3: `[assembly: CaptureConsole]` and other v3-only assembly attributes 6. **Inventory state shared between tests** -- static fields/properties, singletons, file paths, well-known ports, in-memory caches, database connection strings pointing at a single shared DB, environment variables. Whether parallelization is on or off, switching frameworks changes the *order* and *concurrency* in which these are touched. List them now so you can decide in Step 11 whether to enable parallelism, serialize specific classes with `[DoNotParallelize]`, or refactor the shared state. 7. Run a baseline build + test to record the current pass/fail count for parity check at Step 13. Re-run a second time -- if the xUnit run is **flaky** today, those flakes are almost certainly caused by parallel scheduling and will manifest differently after migration. Flag any flaky tests now. ### Step 2: Replace packages > Choose the package option that matches what the project uses today. **When the user says "preserve VSTest" -- or the existing project uses explicit `PackageReference`s -- default to Option A (`MSTest` metapackage).** Reach for Option B (`MSTest.Sdk`) only when the user explicitly asks to modernize the SDK or already uses `MSTest.Sdk` elsewhere in the solution; if you adopt it, you must preserve the platform from Step 1. **Remove** every xUnit package reference (from `.csproj`, `Directory.Build.props`, `Directory.Packages.props`): - `xunit`, `xunit.abstractions`, `xunit.assert`, `xunit.core` - `xunit.extensibility.core`, `xunit.extensibility.execution` - `xunit.runner.visualstudio` - `xunit.v3`, `xunit.v3.assert`, `xunit.v3.core`, `xunit.v3.extensibility.core` - `xunit.v3.mtp-v1`, `xunit.v3.mtp-v2`, `xunit.v3.core.mtp-v1`, `xunit.v3.core.mtp-v2` - `YTest.MTP.XUnit2` (xUnit v2 MTP shim) - Companion packages: `Xunit.SkippableFact`, `Xunit.Combinatorial`, `Xunit.StaFact` (see Step 10) **Add** MSTest v4. Two options -- both correct. **Option A -- `MSTest` metapackage (recommended for incremental migrations):** ```xml <ItemGroup> <PackageReference Include="MSTest" Version="4.1.0" /> </ItemGroup> ``` The `MSTest` metapackage pulls in `MSTest.TestFramework`, `MSTest.TestAdapter`, `MSTest.Analyzers`, and `Microsoft.NET.Test.Sdk` -- so VSTest discovery (`vstest.console`, classic `dotnet test`) still works. > **MTP code-coverage caveat for Option A:** `Microsoft.NET.Test.Sdk` pulls VSTest's `Microsoft.CodeCoverage` transitively. If the project from Step 1 is on **MTP** and uses code coverage, that transitive dependency can interfere with MTP's collector (`Microsoft.Testing.Extensions.CodeCoverage`). Prefer **Option B** (`MSTest.Sdk` without `UseVSTest`) for MTP projects -- the SDK omits `Microsoft.NET.Test.Sdk` and wires the MTP coverage collector instead. If you must stay on Option A for an MTP project, verify coverage works on a representative test run before merging. **Option B -- `MSTest.Sdk`:** ```xml <Project Sdk="MSTest.Sdk/4.1.0"> <PropertyGroup> <!-- Keep the project's existing TargetFramework -- do NOT retarget during migration. --> <TargetFramework>$(ExistingTargetFramework)</TargetFramework> </PropertyGroup> </Project> ``` `MSTest.Sdk` defaults to **MTP**. To preserve a VSTest project, opt back in with `<UseVSTest>true</UseVSTest>` -- the SDK then pulls in `Microsoft.NET.Test.Sdk` automatically (no extra `PackageReference` needed): ```xml <PropertyGroup> <UseVSTest>true</UseVSTest> </PropertyGroup> ``` For solutions with several test projects, prefer pinning the `MSTest.Sdk` version in `global.json` so it lives in one place: ```json { "msbuild-sdks": { "MSTest.Sdk": "4.1.0" } } ``` With the pin in `global.json`, the project line simplifies to `<Project Sdk="MSTest.Sdk">`. When switching to `MSTest.Sdk`, also remove now-redundant properties: `<OutputType>Exe</OutputType>`, `<IsPackable>false</IsPackable>`, `<IsTestProject>true</IsTestProject>`, `<EnableMSTestRunner>`. `MSTest.Sdk` also adds `Microsoft.VisualStudio.TestTools.UnitTesting` as an **implicit global using**. Do **not** add `<Using Include="Microsoft.VisualStudio.TestTools.UnitTesting" />` to the project (it's noise) and skip the per-file `using Microsoft.VisualStudio.TestTools.UnitTesting;` in Step 4 -- you only need it for projects on Option A (the `MSTest` metapackage). ### Step 3: Update project configuration 1. **Preserve the runner.** Confirm the platform decision from Step 1 still holds after Step 2. Common mistakes: - Switching to `MSTest.Sdk` without `UseVSTest=true` silently flips a VSTest project to MTP. Add `<UseVSTest>true</UseVSTest>` to the project (the SDK pulls in `Microsoft.NET.Test.Sdk` automatically -- no manual `PackageReference` needed). - `<UseMicrosoftTestingPlatformRunner>true</UseMicrosoftTestingPlatformRunner>` only affects the `dotnet run` entry point and is **not** a runner switch in Test Explorer or `dotnet test`. Do not infer the platform from this property in either direction -- defer to the `platform-detection` skill (see Step 1). 2. Delete `xunit.runner.json` and port any settings you need (parallelization, `[CollectionBehavior]`, `appDomain`) per Step 11's "xunit.runner.json -> MSTest" sub-table. The settings have no direct MSBuild-property mapping. 3. Remove `using Xunit;` and `using Xunit.Abstractions;` from C# files. For **Option A** (`MSTest` metapackage), add `using Microsoft.VisualStudio.TestTools.UnitTesting;` per file (Step 4 covers this alongside the other rewrites). For **Option B** (`MSTest.Sdk`), skip the per-file using -- the SDK provides it as an implicit global using. ### Step 4: Convert test classes and methods Apply these rewrites to every C# test file. Class-level first, then method-level. **Class:** - Add `[TestClass]` to every class that contained xUnit `[Fact]`/`[Theory]` methods (xUnit had no class-level requirement). - **Preserve the original class hierarchy.** xUnit projects often use base/derived test classes (shared setup, helper assertions, generic base fixtures); marking classes `sealed` would break that pattern. Sealing is an optional follow-up handled by `writing-mstest-tests`, not part of the mechanical migration. - Replace `using Xunit;` / `using Xunit.Abstractions;` with `using Microsoft.VisualStudio.TestTools.UnitTesting;`. **On Option B (`MSTest.Sdk`), skip adding the MSTest using** -- the SDK provides it as an implicit global using, so just remove the `using Xunit;` / `using Xunit.Abstractions;` lines (Step 2 and Step 3 cover this). **Methods:** > **`[Ignore]` and `[Timeout]` are modifiers, not discovery attributes.** Always emit `[TestMethod]` *alongside* them -- a method with `[Ignore]` but no `[TestMethod]` is silently skipped by the test runner (no error, no skip count). Same for `[Timeout]`. | xUnit | MSTest | |---|---| | `[Fact]` | `[TestMethod]` | | `[Theory]` | `[TestMethod]` (parameterized; MSTest 3+ no longer needs `[DataTestMethod]`) | | `[Fact(DisplayName = "x")]` | `[TestMethod("x")]` (v3 of MSTest) or `[TestMethod(DisplayName = "x")]` (v4) | | `[Fact(Skip = "reason")]` | `[TestMethod]` + `[Ignore("reason")]` (both attributes required) | | `[Fact(Timeout = 5000)]` | `[TestMethod]` + `[Timeout(5000)]` (both attributes required) | | `[Trait("Category", "Unit")]` | `[TestCategory("Unit")]` |
Ver no GitHub
Este SKILL.md e muito grande, entao o SkillsMP mostra aqui apenas a primeira secao. Ver no GitHub