Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,24 @@ MSTest v3 introduces these breaking changes from v1/v2. Address only the ones re
| Timeout behavior unified across .NET Core / Framework | Tests with `[Timeout]` may behave differently | Verify timeout values; adjust if needed |
| Dropped target frameworks: .NET 5, .NET Fx < 4.6.2, netstandard1.0, UWP < 16299, WinUI < 18362 | Build error | Update TFM: .NET 5 -> net8.0 (LTS) or net6.0+, netfx -> net462+, netstandard1.0 -> netstandard2.0. Note: net6.0, net8.0, net9.0 are all supported |
| Not binary compatible with v1/v2 | Libraries compiled against v1/v2 must be recompiled | Recompile all dependencies against v3 |
| Test ID generation changed | Playlists, filters, or CI history keyed by test ID may reset | Re-baseline IDs and verify affected filters |
| `TargetInvocationException` is unwrapped | Tests or infrastructure expecting the wrapper observe the inner exception | Update exception handling to expect the underlying exception |
| Initialization/cleanup messages now attach to test results | The first/last test output may gain lifecycle messages that were previously absent | Update log processing and inspect the first/last test results |
| Deployment directory behavior is unified across TFMs | Tests with hard-coded deployment paths may fail | Use `TestContext.DeploymentDirectory` or deployed-item paths instead of assumptions |
| Nullable annotations were added | Nullable-enabled projects may gain warnings | Fix the warnings without suppressing unrelated diagnostics |

## Response Guidelines

- **Always identify the current version first**: Before recommending any migration steps, explicitly state the current MSTest version detected in the project (e.g., "Your project uses MSTest v2 (2.2.10)" or "This is an MSTest v1 project using QualityTools assembly references"). This grounds the migration advice and confirms you've read the project files.
- **Require project evidence**: Do not assume v1/v2 from the wording alone. Read project or central package files and classify the source as QualityTools/v1, NuGet 1.x, or NuGet 2.x. If the project is already on v3+, stop and route to the appropriate skill.
- **Preserve the test platform**: Keep VSTest or MTP unchanged during the framework upgrade unless the user separately requests a runner migration.
- **Execute full migrations**: When the user asks you to migrate or upgrade the project, edit the files, build, and run tests. Do not stop after listing breaking changes. Advice-only responses are appropriate only when the user asks what to expect.
- **Focused fix requests** (user has specific compilation errors after upgrading): Address only the relevant breaking change from the table above. Show a concise before/after fix. Do not walk through the full migration workflow.
- **Specific feature migration** (user asks about one aspect like .testsettings, DataRow, or assertions): Address only that specific aspect with a concrete fix. Do not walk through the entire migration workflow or unrelated breaking changes.
- **"What to expect" questions** (user asks about breaking changes before upgrading): Present only the breaking changes that are clearly relevant to the user's visible code and configuration. For each, give a one-line fix summary. Do not include every possible breaking change -- only the ones that apply. Do not walk through the full workflow.
- **Specific feature migration** (user asks about one aspect like .testsettings, DataRow, or assertions): Address only that feature, but handle every active setting or affected usage in the supplied files. For `.testsettings`, map requested deployment, timeout, data collector, and other active configuration rather than stopping after the first setting. Do not walk through unrelated breaking changes.
- **"What to expect" questions** (user asks about breaking changes before upgrading): Summarize every category in the Breaking Changes Summary, marking which ones directly apply to the visible project. Keep each item to one line and do not expand into release-note history.
- **Full migration requests** (user wants complete migration): Follow the complete workflow below.
- **Comparison questions** (user asks about v1 vs v2 differences): Explain concisely -- v1 uses assembly references and requires removing them first; v2 uses NuGet and just needs a version bump. Both converge on the same v3 packages and breaking changes.
- **Keep findings project-specific**: Report only breaking changes found in the visible code/configuration. Do not dump the full compatibility table into every response.
- **Keep execution project-specific**: For fixes and full migrations, change only patterns found in the visible code/configuration. Broader coverage is reserved for explicit "what should I expect?" questions.

## Migration Paths

Expand All @@ -82,13 +88,11 @@ Both paths converge at Step 3 -- the same v3 packages and breaking changes apply

### Step 1: Assess the project

1. Identify which MSTest version is currently in use:
1. In one discovery pass, batch-read project and central configuration files, search for affected APIs/settings, and identify which MSTest version is currently in use:
- **Assembly reference**: Look for `Microsoft.VisualStudio.QualityTools.UnitTestFramework` in project references -> MSTest v1
- **NuGet packages**: Check `MSTest.TestFramework` and `MSTest.TestAdapter` package versions -> v1 if 1.x, v2 if 2.x
2. Read `Directory.Packages.props`, `Directory.Build.props`, and imported props/targets before editing; package versions may be centralized.
3. Check whether the project uses `.testsettings` / `<LegacySettings>`, affected assertions, `DataRow`, or `[Timeout]`.
4. Check if the target framework is dropped in v3 (see Step 4).
5. Run the existing build and test command. Record discovered, passed, failed, and skipped counts as the parity baseline.
2. Check whether the target framework is dropped in v3 (see Step 4).
3. Run the existing test command. Record discovered, passed, failed, and skipped counts as the parity baseline.

### Step 2: Remove v1 assembly references (if applicable)

Expand All @@ -115,9 +119,9 @@ Keep `Microsoft.NET.Test.Sdk` when the project remains on VSTest, but update it

**Use MSTest.Sdk only when the user requests it or the repository already standardizes on it (SDK-style projects only):**

Change `<Project Sdk="Microsoft.NET.Sdk">` to `<Project Sdk="MSTest.Sdk/3.8.0">`. MSTest.Sdk automatically provides MSTest.TestFramework, MSTest.TestAdapter, MSTest.Analyzers, and Microsoft.NET.Test.Sdk.
Change `<Project Sdk="Microsoft.NET.Sdk">` to `<Project Sdk="MSTest.Sdk/3.8.0">`. MSTest.Sdk automatically provides the MSTest framework, adapter, and analyzers.

> **Important**: MSTest.Sdk defaults to Microsoft.Testing.Platform (MTP) instead of VSTest. For VSTest compatibility (e.g., `vstest.console` in CI), add `<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />`.
> **Important**: MSTest.Sdk defaults to Microsoft.Testing.Platform (MTP). When preserving VSTest, set `<UseVSTest>true</UseVSTest>`; the SDK then supplies the required `Microsoft.NET.Test.Sdk` reference. Do not switch runners merely as a side effect of the framework upgrade.

When switching to MSTest.Sdk, remove these (SDK provides them automatically):

Expand Down Expand Up @@ -177,11 +181,10 @@ Key mappings:

### Step 7: Verify

1. Run `dotnet build` -- confirm zero errors and review any new warnings
2. Run the same test command, filter, and configuration used for the baseline
3. Compare discovered, passed, failed, and skipped counts to the pre-migration baseline
4. Investigate every count difference; do not accept silently dropped tests or data rows
5. Confirm no QualityTools reference, 1.x/2.x MSTest package, `.testsettings`, or `<LegacySettings>` remains
1. Run the same test command, filter, and configuration used for the baseline. `dotnet test` builds by default; run a separate build only to isolate a compilation failure.
2. Compare discovered, passed, failed, and skipped counts to the pre-migration baseline.
3. Investigate every count difference; do not accept silently dropped tests or data rows.
4. Confirm no QualityTools reference, 1.x/2.x MSTest package, `.testsettings`, or `<LegacySettings>` remains.

## Validation

Expand All @@ -198,5 +201,5 @@ After v3 migration, use `migrate-mstest-v3-to-v4` for MSTest v4.

| Pitfall | Solution |
|---------|----------|
| Missing `Microsoft.NET.Test.Sdk` | Add package reference -- required for test discovery with VSTest |
| MSTest.Sdk tests not found by `vstest.console` | MSTest.Sdk defaults to Microsoft.Testing.Platform; add explicit `Microsoft.NET.Test.Sdk` for VSTest compatibility |
| Non-MSTest.Sdk VSTest project missing `Microsoft.NET.Test.Sdk` | Add the package reference for VSTest discovery |
| MSTest.Sdk tests not found by `vstest.console` | Set `<UseVSTest>true</UseVSTest>`; MSTest.Sdk then supplies `Microsoft.NET.Test.Sdk` |
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,31 @@ Do not combine this framework conversion with a target-framework upgrade or VSTe
- **Focused compile error or API question:** inspect the relevant code and apply only that mapping. Do not narrate the entire workflow.
- **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 as the intermediate target.

For detailed mappings and examples, load [`references/mapping-cheatsheet.md`](references/mapping-cheatsheet.md) only for constructs actually present in the project. Do not reproduce the whole reference in the response.
For detailed mappings and examples, search [`references/mapping-cheatsheet.md`](references/mapping-cheatsheet.md) for constructs actually present in the project and read only the matching sections. Do not load or reproduce the whole reference.

## Fast Path

For a routine project migration, converge in four phases: one batched discovery read/search, one edit pass, one `dotnet test`, and one concise result. Do not:

- list a directory and then reread the same files through another tool
- try `dotnet test --no-restore` unless restore is already known to be current
- run separate restore, build, and test commands when `dotnet test` is sufficient
- rerun a passing test command or inspect unchanged files for confirmation

Use an existing CI/test result as the parity baseline when available. Run a new pre-edit baseline only when counts are unavailable and the migration contains data-driven tests, fixtures, skips, custom extensions, shared state, or other behavior whose parity cannot be established from source alone.

## Workflow

### 1. Establish the baseline

1. Read the test projects plus `Directory.Build.props`, `Directory.Packages.props`, `global.json`, and runner configuration.
1. In one discovery pass, batch-read the test projects plus `Directory.Build.props`, `Directory.Packages.props`, `global.json`, and runner configuration, and search the source for the high-risk constructs below.
2. State the detected source version:
- `xunit` 2.x and related packages -> xUnit v2
- `xunit.v3` or `xunit.v3.*` -> xUnit v3
3. Use `platform-detection` to identify VSTest or MTP. Preserve that platform.
3. Identify VSTest or MTP from the project and repository configuration. Use `platform-detection` only when the platform is ambiguous, and preserve the detected platform.
4. Record the target frameworks and stop if MSTest v4 does not support them.
5. Run the existing build and test command. Record discovered, passed, failed, and skipped counts.
6. Search for high-risk constructs before editing:
5. If the Fast Path requires a new baseline, run the existing test command once and record discovered, passed, failed, and skipped counts.
6. Inventory high-risk constructs before editing:
- `IClassFixture`, `ICollectionFixture`, `CollectionDefinition`, custom `FactAttribute`/`TheoryAttribute`/`DataAttribute`
- `Assert.Throws`, `ThrowsAny`, `IsType`, `Record.Exception`, event assertions
- `ITestOutputHelper`, `TestContext.Current`, `IAsyncLifetime`
Expand All @@ -55,7 +66,7 @@ Default to the MSTest v4 metapackage for an incremental conversion:
<PackageReference Include="MSTest" Version="4.1.0" />
```

This keeps VSTest available through `Microsoft.NET.Test.Sdk`. Use `MSTest.Sdk` only when the project already uses it elsewhere or the user explicitly requests it. `MSTest.Sdk` defaults to MTP, so add `<UseVSTest>true</UseVSTest>` when preserving VSTest.
This keeps VSTest available through the metapackage's compatible `Microsoft.NET.Test.Sdk` dependency. Remove a stale explicit `Microsoft.NET.Test.Sdk` reference or update it to the minimum required by the chosen MSTest version (MSTest 4.1.0 requires 18.0.1+); otherwise restore fails with `NU1605`. Use `MSTest.Sdk` only when the project already uses it elsewhere or the user explicitly requests it. `MSTest.Sdk` defaults to MTP, so add `<UseVSTest>true</UseVSTest>` when preserving VSTest.

Do not change `TargetFramework`. Remove `xunit.runner.json` only after porting its relevant settings.

Expand Down Expand Up @@ -87,12 +98,13 @@ Load the mapping cheatsheet for every high-risk construct found in Step 1. These
- xUnit `Assert.Throws<T>` is exact-type and maps to MSTest `Assert.ThrowsExactly<T>`.
- xUnit `Assert.ThrowsAny<T>` permits derived types and maps to MSTest `Assert.Throws<T>`.
- xUnit `Assert.IsType<T>` is exact-type and maps to `Assert.IsExactInstanceOfType<T>`; `Assert.IsAssignableFrom<T>` maps to `Assert.IsInstanceOfType<T>`.
- xUnit `Assert.Equal` on sequences compares elements. Use `Assert.AreSequenceEqual` on MSTest 4.3+ or `CollectionAssert.AreEqual` with materialized lists on earlier v4; never replace sequence equality with reference-based `Assert.AreEqual`.
- `[Ignore]` and `[Timeout]` are modifiers; keep `[TestMethod]` so the test is discovered.
- `[DataRow]` values must exactly match parameter types.
- `TestContext.Current.CancellationToken` maps to an injected MSTest `TestContext.CancellationToken`; never replace it with `CancellationToken.None` or a new `CancellationTokenSource`.
- Assertions with no MSTest equivalent (`Assert.Collection`, `Assert.All`, `Assert.Equivalent`, `Record.Exception`, event assertions) require an explicit manual rewrite. Never delete an assertion without replacing its verification.

Build after the mechanical pass. Use compiler errors plus the inventory to drive only the remaining conversions.
Apply the mechanical and semantic rewrites in one edit pass when the inventory makes the required mappings clear. Do not run an intermediate build by default; use compiler errors from final verification to drive only unresolved conversions.

### 5. Preserve lifecycle, fixture scope, and parallelization

Expand All @@ -111,15 +123,14 @@ Never use `ExecutionScope.MethodLevel` to emulate xUnit. Before applying a fixtu

### 6. Verify parity

1. Run the build; it must complete with zero errors.
2. Run tests with the same platform, filter, and configuration used for the baseline.
3. Compare discovered, passed, failed, and skipped counts.
4. Investigate every difference before declaring completion:
1. Run tests once with the same platform, filter, and configuration used for the baseline. `dotnet test` builds by default; run a separate build only when needed to isolate a compilation failure.
2. Compare discovered, passed, failed, and skipped counts.
3. Investigate every difference before declaring completion:
- missing cases -> discovery attributes, `DynamicData`, or `DataRow` literal types
- changed exception behavior -> exact-vs-derived assertion mapping
- shared-state failures or large duration changes -> fixture scope and parallelization
- silently skipped tests -> missing `[TestMethod]` or incorrect runtime-skip conversion
5. Confirm no xUnit package, namespace, attribute, runner configuration, or fixture interface remains unless explicitly documented for manual follow-up.
4. Confirm no xUnit package, namespace, attribute, runner configuration, or fixture interface remains unless explicitly documented for manual follow-up.

## Completion Criteria

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,8 @@ xUnit assembly attributes split into two groups: a few have direct MSTest equiva
<PackageReference Include="MSTest" Version="4.1.0" />
```

Remove an older explicit `Microsoft.NET.Test.Sdk` reference or update it to 18.0.1+; keeping 17.x alongside MSTest 4.1.0 causes `NU1605`.

```xml
<!-- Option B: MSTest.Sdk -- defaults to MTP; set <UseVSTest>true</UseVSTest> to preserve VSTest. -->
<!-- UseVSTest pulls in Microsoft.NET.Test.Sdk automatically -- no extra PackageReference needed. -->
Expand Down
Loading
Loading