/migrate-nunit-to-mstest
Convert .NET tests from NUnit 3/4 to MSTest v4 while preserving VSTest or MTP. Use for replacing NUnit/NUnit3TestAdapter packages, Test/TestCase/ TestCaseSource/Values attributes, constraint assertions, SetUp/TearDown, OneTimeSetUp, SetUpFixture, FixtureLifeCycle, TestContext,
Claude Code
$ npx -y skills add dotnet/skills --skill migrate-nunit-to-mstest --agent claude-code
Codex
$ npx skills add dotnet/skills --skill migrate-nunit-to-mstest -a codex -y
Cursor
$ npx skills add dotnet/skills --skill migrate-nunit-to-mstest -a cursor -y
Gemini CLI
$ npx skills add dotnet/skills --skill migrate-nunit-to-mstest -a gemini-cli -y
GitHub Copilot
$ npx skills add dotnet/skills --skill migrate-nunit-to-mstest -a github-copilot -y
OpenCode
$ npx skills add dotnet/skills --skill migrate-nunit-to-mstest -a opencode -y
Windsurf
$ npx skills add dotnet/skills --skill migrate-nunit-to-mstest -a windsurf -y
SKILL.md
migrate-nunit-to-mstest.SKILL.mdname: migrate-nunit-to-mstest
description: >
Convert .NET tests from NUnit 3/4 to MSTest v4 while preserving VSTest or
MTP. Use for replacing NUnit/NUnit3TestAdapter packages, Test/TestCase/
TestCaseSource/Values attributes, constraint assertions, SetUp/TearDown,
OneTimeSetUp, SetUpFixture, FixtureLifeCycle, TestContext, categories,
retries, timeouts, and NUnit parallelization. Also use when a "convert NUnit
to MSTest" request may already be migrated: inspect and report the no-op. Do
not use for NUnit version upgrades, xUnit/TUnit conversion, MSTest upgrades,
or runner-only VSTest-to-MTP migration.
license: MIT
NUnit -> MSTest Migration
Convert NUnit 3 or 4 tests to MSTest v4 without changing the target framework or test platform. A successful migration builds, discovers the same test cases, and preserves pass/fail, lifecycle, data, filtering, and concurrency semantics.
Scope
Use this skill only when the project contains NUnit packages or source and the user wants MSTest. If the project already uses MSTest and contains no NUnit tests, report that no framework migration is needed and make no changes.
Do not combine this framework conversion with a target-framework upgrade or VSTest/MTP migration. Complete and verify one migration before starting another.
Workspace Contract
- Search the current working directory for projects and source; never look for user files under this skill's directory.
- Classify the deliverable: "convert this project" means edit, build, and test; "give me a plan" means answer without editing.
- Preserve the user's requested project scope. Shared props may be changed only when they own NUnit package or runner configuration for that scope.
- The final response must state the source NUnit version, preserved runner, changed files, high-risk semantic mappings, and actual test counts.
Response Mode
- **Full migration request:** inspect, edit, build, and run tests. Do not stop after a plan.
- **Focused compile error or API question:** apply only the relevant mapping.
- **Unsupported target framework:** stop before changing packages. MSTest v4 requires .NET 8+ or .NET Framework 4.6.2+ for test applications; offer a separately approved TFM upgrade or MSTest v3.
Decisions That Change the Result
| Detected state | Required action | |---|---| | No NUnit package, namespace, attribute, or constraint remains | Stop, make no changes, and run the existing test command once to prove the already-MSTest project is healthy. | | Source uses VSTest | Preserve VSTest. Retain and update an explicit `Microsoft.NET.Test.Sdk` pin when the repository owns one; do not introduce MTP properties. | | Source uses MTP | Replace NUnit-specific MTP configuration with MSTest MTP configuration. Prefer `MSTest.Sdk`; with the metapackage set `EnableMSTestRunner=true` and `OutputType=Exe`. | | NUnit uses its default fixture lifecycle | NUnit normally shares one fixture instance across all test cases; MSTest creates a new class instance per test. Move state that must remain class-shared behind static fields initialized by `[ClassInitialize]`, or prove the state is per-test before leaving it as an instance field. | | NUnit has no `Parallelizable` configuration | Preserve serial execution. Do not add `[assembly: Parallelize]`; NUnit and MSTest are both serial by default. | | NUnit explicitly enables parallel execution | Translate the effective scope and worker count. Never infer method-level parallelism from fixture-level settings. |
For detailed mappings, search [`references/mapping-cheatsheet.md`](references/mapping-cheatsheet.md) for constructs present in the project and read only those sections.
Fast Path
For a routine migration, converge in four phases: one batched discovery pass, one edit pass, one `dotnet test`, and one concise result.
- Use an existing CI/test result as the baseline when available.
- Run a pre-edit baseline when counts are unavailable and the project contains parameterized tests, fixture state, namespace setup, retries, custom attributes, or explicit parallelization.
- Do not run separate restore, build, and test commands when `dotnet test` is sufficient.
- Do not delete NUnit runner configuration until its behavior has been translated.
Workflow
1. Establish the baseline
1. Batch-read test projects, central package files, `global.json`, `.runsettings`, `testconfig.json`, and NUnit configuration. 2. Detect NUnit from `NUnit`, `NUnit3TestAdapter`, `NUnit.Analyzers`, `NUnit.Framework`, `NUnit.Framework.Legacy`, and `using NUnit.Framework`. 3. State whether the source is NUnit 3 or 4 from the resolved package version. 4. Detect VSTest or MTP and preserve it. Use `platform-detection` only when ambiguous. 5. Record target frameworks and stop if MSTest v4 does not support them. 6. Inventory high-risk constructs:
- `[TestFixture(...)]`, `[TestFixtureSource]`, `[FixtureLifeCycle]`, constructors with parameters
- `[TestCase]`, `[TestCaseSource]`, `TestCaseData`, `[Values]`, `[Range]`, `[Random]`, `[Sequential]`, `[Pairwise]`, custom data attributes
- `[Theory]`, `[Datapoint]`, `[DatapointSource]`, automatic bool/enum datapoints, `Assume.That`
- `[OneTimeSetUp]`, `[OneTimeTearDown]`, `[SetUpFixture]`, inheritance-based setup
- `Assert.That`, `Assert.Multiple`, `Assert.Throws`, `Assert.Catch`, collection constraints
- `[Parallelizable]`, `[NonParallelizable]`, `[LevelOfParallelism]`, `[Order]`, `[SingleThreaded]`
- `[Apartment]`, `[RequiresThread]`, `[CancelAfter]`, `[Timeout]`
- `[Culture]`, `[Platform]`, `[SetCulture]`, `[SetUICulture]`
- `[Explicit]`, `[Repeat]`, `[Retry]`, `[MaxTime]`, categories, properties, `[TestOf]`
- `[DefaultFloatingPointTolerance]`, `[NonTestAssembly]`, and deprecated fixture lifecycle aliases
2. Replace packages without switching runners
Remove NUnit-specific packages being replaced, including `NUnit`, `NUnit3TestAdapter`, `NUnit.Analyzers`, NUnit console runner packag
Read more
name: migrate-nunit-to-mstest description: > Convert .NET tests from NUnit 3/4 to MSTest v4 while preserving VSTest or MTP. Use for replacing NUnit/NUnit3TestAdapter packages, Test/TestCase/ TestCaseSource/Values attributes, constraint assertions, SetUp/TearDown, OneTimeSetUp, SetUpFixture, FixtureLifeCycle, TestContext, categories, retries, timeouts, and NUnit parallelization. Also use when a "convert NUnit to MSTest" request may already be migrated: inspect and report the no-op. Do not use for NUnit version upgrades, xUnit/TUnit conversion, MSTest upgrades, or runner-only VSTest-to-MTP migration. license: MIT
NUnit -> MSTest Migration
Convert NUnit 3 or 4 tests to MSTest v4 without changing the target framework or test platform. A successful migration builds, discovers the same test cases, and preserves pass/fail, lifecycle, data, filtering, and concurrency semantics.
Scope
Use this skill only when the project contains NUnit packages or source and the user wants MSTest. If the project already uses MSTest and contains no NUnit tests, report that no framework migration is needed and make no changes.
Do not combine this framework conversion with a target-framework upgrade or VSTest/MTP migration. Complete and verify one migration before starting another.
Workspace Contract
- Search the current working directory for projects and source; never look for user files under this skill's directory.
- Classify the deliverable: "convert this project" means edit, build, and test; "give me a plan" means answer without editing.
- Preserve the user's requested project scope. Shared props may be changed only when they own NUnit package or runner configuration for that scope.
- The final response must state the source NUnit version, preserved runner, changed files, high-risk semantic mappings, and actual test counts.
Response Mode
- **Full migration request:** inspect, edit, build, and run tests. Do not stop after a plan.
- **Focused compile error or API question:** apply only the relevant mapping.
- **Unsupported target framework:** stop before changing packages. MSTest v4 requires .NET 8+ or .NET Framework 4.6.2+ for test applications; offer a separately approved TFM upgrade or MSTest v3.
Decisions That Change the Result
| Detected state | Required action | |---|---| | No NUnit package, namespace, attribute, or constraint remains | Stop, make no changes, and run the existing test command once to prove the already-MSTest project is healthy. | | Source uses VSTest | Preserve VSTest. Retain and update an explicit `Microsoft.NET.Test.Sdk` pin when the repository owns one; do not introduce MTP properties. | | Source uses MTP | Replace NUnit-specific MTP configuration with MSTest MTP configuration. Prefer `MSTest.Sdk`; with the metapackage set `EnableMSTestRunner=true` and `OutputType=Exe`. | | NUnit uses its default fixture lifecycle | NUnit normally shares one fixture instance across all test cases; MSTest creates a new class instance per test. Move state that must remain class-shared behind static fields initialized by `[ClassInitialize]`, or prove the state is per-test before leaving it as an instance field. | | NUnit has no `Parallelizable` configuration | Preserve serial execution. Do not add `[assembly: Parallelize]`; NUnit and MSTest are both serial by default. | | NUnit explicitly enables parallel execution | Translate the effective scope and worker count. Never infer method-level parallelism from fixture-level settings. |
For detailed mappings, search [`references/mapping-cheatsheet.md`](references/mapping-cheatsheet.md) for constructs present in the project and read only those sections.
Fast Path
For a routine migration, converge in four phases: one batched discovery pass, one edit pass, one `dotnet test`, and one concise result.
- Use an existing CI/test result as the baseline when available.
- Run a pre-edit baseline when counts are unavailable and the project contains parameterized tests, fixture state, namespace setup, retries, custom attributes, or explicit parallelization.
- Do not run separate restore, build, and test commands when `dotnet test` is sufficient.
- Do not delete NUnit runner configuration until its behavior has been translated.
Workflow
1. Establish the baseline
1. Batch-read test projects, central package files, `global.json`, `.runsettings`, `testconfig.json`, and NUnit configuration. 2. Detect NUnit from `NUnit`, `NUnit3TestAdapter`, `NUnit.Analyzers`, `NUnit.Framework`, `NUnit.Framework.Legacy`, and `using NUnit.Framework`. 3. State whether the source is NUnit 3 or 4 from the resolved package version. 4. Detect VSTest or MTP and preserve it. Use `platform-detection` only when ambiguous. 5. Record target frameworks and stop if MSTest v4 does not support them. 6. Inventory high-risk constructs:
- `[TestFixture(...)]`, `[TestFixtureSource]`, `[FixtureLifeCycle]`, constructors with parameters
- `[TestCase]`, `[TestCaseSource]`, `TestCaseData`, `[Values]`, `[Range]`, `[Random]`, `[Sequential]`, `[Pairwise]`, custom data attributes
- `[Theory]`, `[Datapoint]`, `[DatapointSource]`, automatic bool/enum datapoints, `Assume.That`
- `[OneTimeSetUp]`, `[OneTimeTearDown]`, `[SetUpFixture]`, inheritance-based setup
- `Assert.That`, `Assert.Multiple`, `Assert.Throws`, `Assert.Catch`, collection constraints
- `[Parallelizable]`, `[NonParallelizable]`, `[LevelOfParallelism]`, `[Order]`, `[SingleThreaded]`
- `[Apartment]`, `[RequiresThread]`, `[CancelAfter]`, `[Timeout]`
- `[Culture]`, `[Platform]`, `[SetCulture]`, `[SetUICulture]`
- `[Explicit]`, `[Repeat]`, `[Retry]`, `[MaxTime]`, categories, properties, `[TestOf]`
- `[DefaultFloatingPointTolerance]`, `[NonTestAssembly]`, and deprecated fixture lifecycle aliases
2. Replace packages without switching runners
Remove NUnit-specific packages being replaced, including `NUnit`, `NUnit3TestAdapter`, `NUnit.Analyzers`, NUnit console runner packag
This repository contains the .NET team's curated set of portable skills and host-specific custom agents for coding agents. For information about the Agent Skills standard, see agentskills.io.
Other skills on skills.
More skills from other plugins.
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
ask-matt
Ask which skill or flow fits your situation. A router over the skills in this repo.
Questions about migrate-nunit-to-mstest.
- Which coding agents can use migrate-nunit-to-mstest?
- migrate-nunit-to-mstest installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

