# How the dotnet-test-migration Plugin Handles Test Migration in .NET Projects

> Learn how the dotnet-test-migration plugin expertly handles test migration in .NET projects. Discover its three-phase workflow for seamless framework updates and safe, buildable results.

- Repository: [.NET Platform/skills](https://github.com/dotnet/skills)
- Tags: how-to-guide
- Published: 2026-07-06

---

**The dotnet-test-migration plugin orchestrates test migration through a three-phase workflow involving detection of current frameworks, routing to specialized migration skills, and step-by-step execution with safety guardrails that ensure the repository remains buildable and test-passing after each commit.**

The dotnet-test-migration plugin, part of the **dotnet/skills** repository, automates the complex process of upgrading .NET test frameworks and switching test runner platforms. It supports migrations between MSTest, xUnit, NUnit, and TUnit, as well as transitions from VSTest to the Microsoft.Testing.Platform. The implementation relies on a deterministic agent-based architecture defined in [`plugins/dotnet-test-migration/agents/test-migration.agent.md`](https://github.com/dotnet/skills/blob/main/plugins/dotnet-test-migration/agents/test-migration.agent.md) and specialized skill definitions for each migration path.

## Detection Phase: Identifying Test Frameworks and Platforms

The migration process begins with an automated detection workflow that scans repository files to determine the current test configuration. The agent examines `*.csproj`, `Directory.Build.props`, `Directory.Packages.props`, and [`global.json`](https://github.com/dotnet/skills/blob/main/global.json) files to extract three critical data points:

- **Test Framework Identity**: Identifies whether the project uses MSTest, xUnit, NUnit, or TUnit.
- **Framework Version**: Distinguishes between major versions, such as MSTest v2 versus v3, or xUnit v2 versus v3.
- **Test Runner Platform**: Determines if tests run on VSTest or the newer Microsoft.Testing.Platform.

This detection logic serves as the foundation for all subsequent routing decisions, ensuring the plugin applies the correct migration strategy based on the actual state of the codebase rather than user assumptions.

## Routing Logic: Selecting the Appropriate Migration Skill

Once detection completes, the agent consults a routing table (defined in [`test-migration.agent.md`](https://github.com/dotnet/skills/blob/main/test-migration.agent.md) lines 46-53) to select the appropriate migration **skill**. Each skill represents a complete, atomic migration path between specific framework or platform versions:

- `migrate-mstest-v1v2-to-v3` – Upgrades legacy MSTest installations to version 3.
- `migrate-mstest-v3-to-v4` – Advances MSTest from version 3 to version 4.
- `migrate-xunit-to-xunit-v3` – Updates xUnit from version 2 to version 3.
- `migrate-xunit-to-mstest` – Converts xUnit test suites to MSTest version 4.
- `migrate-vstest-to-mtp` – Migrates the test execution platform from VSTest to Microsoft.Testing.Platform.

Each skill is documented in its own [`SKILL.md`](https://github.com/dotnet/skills/blob/main/SKILL.md) file within the `plugins/dotnet-test-migration/skills/` directory, containing framework-specific transformation rules and validation steps.

## Execution and Safety Rules

Every migration skill follows a standardized, multi-step execution pattern designed to maintain repository integrity throughout the transformation process.

### Multi-Step Migration Workflow

The detailed workflow defined in each skill's [`SKILL.md`](https://github.com/dotnet/skills/blob/main/SKILL.md) file typically spans thirteen distinct steps:

1. **Project Assessment** – Verifies the target Target Framework Moniker (TFM) compatibility and inventories high-risk patterns such as parallelization, shared fixtures, and test state dependencies.
2. **Package Reference Replacement** – Removes legacy NuGet packages (e.g., xUnit assemblies) and introduces modern equivalents (e.g., MSTest metapackage or `MSTest.Sdk`).
3. **Configuration Conversion** – Updates project files and SDK references to support the new framework capabilities.
4. **Code Transformation** – Converts test classes, methods, data-driven tests, assertions, fixtures, output helpers, and assembly-level attributes to match the target framework's API surface.
5. **Verification** – Executes the build, runs the full test suite, and compares pass/fail counts against the baseline metrics recorded before migration began.

### Safety Guardrails

The agent enforces strict safety rules to prevent destructive changes:

- **Atomic Commits**: Only one migration skill executes per commit, ensuring the project remains buildable and tests remain passing at every step.
- **Parallelization Verification**: Explicitly validates changes to parallel execution behavior, noting that xUnit runs classes in parallel by default while MSTest defaults to serial execution.
- **Scope Communication**: Clearly documents any scope-widening changes, such as converting `ICollectionFixture` to assembly-wide fixtures.
- **Platform Preservation**: Maintains the original test platform unless the user explicitly requests a platform switch, preventing accidental runner changes during framework upgrades.

## Practical Migration Examples

The plugin accepts structured JSON requests to initiate specific migration workflows.

### Example 1: General Test Migration Request

When the user provides an open-ended request, the plugin runs detection to determine the optimal migration path:

```json
{
  "plugin": "dotnet-test-migration",
  "request": "migrate my tests",
  "options": {
    "projectPath": "src/MyApp.Tests.csproj"
  }
}

```

The orchestrator detects xUnit v2 on VSTest and automatically selects the `migrate-xunit-to-mstest` skill. It executes the thirteen-step workflow, creating commits after steps 2, 6, and 8, then reports the final migration summary.

### Example 2: Direct MSTest Version Upgrade

Explicit version upgrade requests bypass detection and route directly to the appropriate skill chain:

```json
{
  "plugin": "dotnet-test-migration",
  "request": "upgrade MSTest to v4",
  "projectPath": "tests/UnitTests.csproj"
}

```

If the current version is v2, the agent queues `migrate-mstest-v1v2-to-v3` followed by `migrate-mstest-v3-to-v4`. Each skill manages its own commit points to ensure a clean, incremental transition.

### Example 3: Platform Migration to Microsoft.Testing.Platform

To switch test runners while preserving the test framework:

```json
{
  "plugin": "dotnet-test-migration",
  "request": "migrate to MTP",
  "projectPath": "tests/IntegrationTests.csproj"
}

```

The agent detects the VSTest runner and routes to `migrate-vstest-to-mtp`. This skill updates the SDK reference, adds `<UseMicrosoftTestingPlatformRunner>true</UseMicrosoftTestingPlatformRunner>` to the project file, and validates the build before committing changes.

## Key Source Files and Architecture

The dotnet-test-migration plugin architecture consists of declarative configuration files and procedural skill definitions:

- **[`plugins/dotnet-test-migration/plugin.json`](https://github.com/dotnet/skills/blob/main/plugins/dotnet-test-migration/plugin.json)**: Declares the plugin metadata, version constraints, and agent registration.
- **[`plugins/dotnet-test-migration/agents/test-migration.agent.md`](https://github.com/dotnet/skills/blob/main/plugins/dotnet-test-migration/agents/test-migration.agent.md)**: Contains the orchestrator logic, detection workflow specifications, routing table (lines 46-53), and global safety rules.
- **[`plugins/dotnet-test-migration/skills/migrate-xunit-to-mstest/SKILL.md`](https://github.com/dotnet/skills/blob/main/plugins/dotnet-test-migration/skills/migrate-xunit-to-mstest/SKILL.md)**: Comprehensive migration guide for converting xUnit test suites to MSTest v4, including attribute mapping and assertion translation.
- **[`plugins/dotnet-test-migration/skills/migrate-mstest-v1v2-to-v3/SKILL.md`](https://github.com/dotnet/skills/blob/main/plugins/dotnet-test-migration/skills/migrate-mstest-v1v2-to-v3/SKILL.md)**: Handles incremental upgrades from legacy MSTest versions to version 3.
- **[`plugins/dotnet-test-migration/skills/migrate-mstest-v3-to-v4/SKILL.md`](https://github.com/dotnet/skills/blob/main/plugins/dotnet-test-migration/skills/migrate-mstest-v3-to-v4/SKILL.md)**: Manages modernization from MSTest v3 to the latest v4 release.
- **[`plugins/dotnet-test-migration/skills/migrate-vstest-to-mtp/SKILL.md`](https://github.com/dotnet/skills/blob/main/plugins/dotnet-test-migration/skills/migrate-vstest-to-mtp/SKILL.md)**: Facilitates the transition from the Visual Studio Test Platform to the lightweight Microsoft.Testing.Platform.
- **[`plugins/dotnet-test-migration/skills/migrate-xunit-to-xunit-v3/SKILL.md`](https://github.com/dotnet/skills/blob/main/plugins/dotnet-test-migration/skills/migrate-xunit-to-xunit-v3/SKILL.md)**: Supports in-place upgrades of xUnit from version 2 to version 3.
- **[`plugins/dotnet-test-migration/skills/migrate-xunit-to-mstest/references/mapping-cheatsheet.md`](https://github.com/dotnet/skills/blob/main/plugins/dotnet-test-migration/skills/migrate-xunit-to-mstest/references/mapping-cheatsheet.md)**: Provides lookup tables for attribute equivalents, assertion mappings, and fixture translations used across all migration skills.

## Summary

- The dotnet-test-migration plugin implements a deterministic three-phase workflow: **detection**, **routing**, and **execution** with strict safety guardrails.
- It supports migrations between MSTest (v1/v2/v3/v4), xUnit (v2/v3), NUnit, and TUnit, plus platform switches between VSTest and Microsoft.Testing.Platform.
- Each migration skill follows a standardized thirteen-step process defined in individual [`SKILL.md`](https://github.com/dotnet/skills/blob/main/SKILL.md) files, ensuring consistency across different framework transformations.
- Safety rules enforce atomic commits, baseline test comparison, and explicit handling of behavioral differences like parallelization settings.
- The routing table in [`test-migration.agent.md`](https://github.com/dotnet/skills/blob/main/test-migration.agent.md) (lines 46-53) automatically selects appropriate skills based on detected project state or explicit user intent.

## Frequently Asked Questions

### What test frameworks does the dotnet-test-migration plugin support?

The plugin supports **MSTest** (versions 1, 2, 3, and 4), **xUnit** (versions 2 and 3), **NUnit**, and **TUnit**. It can migrate between any of these frameworks in either direction, though the most common paths involve upgrading to newer MSTest versions or converting from xUnit to MSTest v4.

### How does the plugin ensure tests still pass after migration?

Each migration skill includes a **verification step** that builds the project and executes the full test suite, comparing pass/fail counts against baseline metrics captured before the migration began. Additionally, the agent enforces **single-migration-per-commit** rules, ensuring the repository remains in a healthy, buildable state throughout the transformation process.

### Can I migrate from xUnit to MSTest using this plugin?

Yes, the `migrate-xunit-to-mstest` skill provides a comprehensive thirteen-step workflow for converting xUnit v2 test suites to MSTest v4. This includes replacing package references with `MSTest.Sdk` or the MSTest metapackage, converting `[Fact]` and `[Theory]` attributes to `[TestMethod]` and `[DataRow]`, transforming assertions, and handling fixture lifecycle differences using the mapping cheatsheet in [`references/mapping-cheatsheet.md`](https://github.com/dotnet/skills/blob/main/references/mapping-cheatsheet.md).

### What is the difference between VSTest and Microsoft.Testing.Platform migration?

**VSTest** (Visual Studio Test Platform) is the legacy test runner integrated with Visual Studio and `dotnet test`. **Microsoft.Testing.Platform** (MTP) is a newer, lighter-weight test execution framework. The `migrate-vstest-to-mtp` skill handles this transition by updating SDK references, adding the `<UseMicrosoftTestingPlatformRunner>true</UseMicrosoftTestingPlatformRunner>` property, and ensuring compatibility with the existing test framework while improving execution performance and reducing overhead.