Add migrate-xunit-to-mstest skill from dotnet/skills#54727
Merged
Evangelink merged 3 commits intoJun 12, 2026
Merged
Conversation
Imports the migrate-xunit-to-mstest skill from dotnet/skills@main (plugins/dotnet-test/skills/migrate-xunit-to-mstest) into this repo so the xUnit -> MSTest migration that's currently in progress (dotnet#54722, dotnet#54723, dotnet#54724, dotnet#54725, dotnet#54726) has a documented, repeatable procedure that contributors and agents can follow consistently. Files added (verbatim from upstream): - .github/skills/migrate-xunit-to-mstest/SKILL.md - .github/skills/migrate-xunit-to-mstest/references/mapping-cheatsheet.md Note: SKILL.md is 546 lines, slightly above the 500-line "Progressive Disclosure" guideline checked by .github/skills/ValidateSkill.cs. The validator is advisory (not CI-enforced) and we are intentionally mirroring the upstream content verbatim to keep future syncs trivial. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
JeremyKuhne
approved these changes
Jun 11, 2026
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new agent skill to document and standardize the ongoing xUnit → MSTest migration workflow in this repo, imported from dotnet/skills, along with a mapping cheatsheet reference.
Changes:
- Add
.github/skills/migrate-xunit-to-mstest/SKILL.mddescribing an end-to-end migration workflow and decision points. - Add
.github/skills/migrate-xunit-to-mstest/references/mapping-cheatsheet.mdwith detailed attribute/assert/fixture/lifecycle mapping tables.
Show a summary per file
| File | Description |
|---|---|
| .github/skills/migrate-xunit-to-mstest/SKILL.md | Adds the primary migration skill workflow and guidance. |
| .github/skills/migrate-xunit-to-mstest/references/mapping-cheatsheet.md | Adds the detailed xUnit→MSTest mapping reference used by the skill. |
Copilot's findings
- Files reviewed: 2/2 changed files
- Comments generated: 4
Evangelink
added a commit
to Evangelink/sdk
that referenced
this pull request
Jun 11, 2026
- Bumps MSTest.Sdk to the latest internal preview to pick up the newest 4.3 assertion APIs (Assert.ContainsSingle, Assert.Contains for strings with the more natural (needle, haystack) signature, etc.). - Applies the assertion mapping flagged by the migrate-xunit-to-mstest skill in this repo (.github/skills/migrate-xunit-to-mstest, PR dotnet#54727): Assert.HasCount(1, x) -> Assert.ContainsSingle(x) (one occurrence in AspireResourceLauncherCliTests.cs) Verified: 58/58 tests still pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Evangelink
added a commit
to Evangelink/sdk
that referenced
this pull request
Jun 11, 2026
…le(x) Applies the assertion mapping flagged by the migrate-xunit-to-mstest skill (.github/skills/migrate-xunit-to-mstest, PR dotnet#54727). Two occurrences in ParserTests.cs converted from `Assert.HasCount(1, parseResult.Errors)` to the more idiomatic `Assert.ContainsSingle(parseResult.Errors)`, which matches the xUnit original (`Assert.Single`) more directly. Verified: 9/9 tests still pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Evangelink
added a commit
to Evangelink/sdk
that referenced
this pull request
Jun 11, 2026
…le(x) Applies the assertion mapping flagged by the migrate-xunit-to-mstest skill (.github/skills/migrate-xunit-to-mstest, PR dotnet#54727). Two occurrences in ParserTests.cs converted from `Assert.HasCount(1, parseResult.Errors)` to the more idiomatic `Assert.ContainsSingle(parseResult.Errors)`, which matches the xUnit original (`Assert.Single`) more directly. Verified: 9/9 tests still pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Evangelink
added a commit
to Evangelink/sdk
that referenced
this pull request
Jun 11, 2026
…tain for strings The migrate-xunit-to-mstest skill (.github/skills/migrate-xunit-to-mstest, PR dotnet#54727) notes that MSTest 3.8+ added Assert.Contains(needle, str) / Assert.DoesNotContain(needle, str) overloads for strings -- with the natural (needle, haystack) argument order matching xUnit's Assert.Contains. With the 4.3.0-preview MSTest.Sdk bump in dotnet#54722, these are now available throughout the migration. Replaced: - StringAssert.Contains(haystack, needle) -> Assert.Contains(needle, haystack) - Assert.IsFalse(haystack.Contains(needle)) -> Assert.DoesNotContain(needle, haystack) Touched files: - BrowserRefreshMiddlewareTest.cs - BrowserScriptMiddlewareTest.cs - ResponseStreamWrapperCompressionTest.cs Note: Assert.IsFalse(dict.ContainsKey(key)) call sites are unchanged (no Assert.DoesNotContainKey API exists). Verified: 110/110 tests still pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This was referenced Jun 11, 2026
Draft
Evangelink
added a commit
to Evangelink/sdk
that referenced
this pull request
Jun 11, 2026
…le(x) Applies the assertion mapping flagged by the migrate-xunit-to-mstest skill (.github/skills/migrate-xunit-to-mstest, PR dotnet#54727). Two occurrences in ParserTests.cs converted from `Assert.HasCount(1, parseResult.Errors)` to the more idiomatic `Assert.ContainsSingle(parseResult.Errors)`, which matches the xUnit original (`Assert.Single`) more directly. Verified: 9/9 tests still pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Evangelink
added a commit
to Evangelink/sdk
that referenced
this pull request
Jun 11, 2026
…tain for strings The migrate-xunit-to-mstest skill (.github/skills/migrate-xunit-to-mstest, PR dotnet#54727) notes that MSTest 3.8+ added Assert.Contains(needle, str) / Assert.DoesNotContain(needle, str) overloads for strings -- with the natural (needle, haystack) argument order matching xUnit's Assert.Contains. With the 4.3.0-preview MSTest.Sdk bump in dotnet#54722, these are now available throughout the migration. Replaced: - StringAssert.Contains(haystack, needle) -> Assert.Contains(needle, haystack) - Assert.IsFalse(haystack.Contains(needle)) -> Assert.DoesNotContain(needle, haystack) Touched files: - BrowserRefreshMiddlewareTest.cs - BrowserScriptMiddlewareTest.cs - ResponseStreamWrapperCompressionTest.cs Note: Assert.IsFalse(dict.ContainsKey(key)) call sites are unchanged (no Assert.DoesNotContainKey API exists). Verified: 110/110 tests still pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Folds learnings discovered while migrating dotnet/sdk to MSTest.Sdk: - MSTest.Sdk implicit global using note - Assert.IsExactInstanceOfType<T> (MSTest 4.1+) for xUnit Assert.IsType<T> - Assert.AreSequenceEqual (MSTest 4.3+) over CollectionAssert.AreEqual - AwesomeAssertions namespace clarification Keeps the sdk-local copy in sync with the upstream PR. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Member
Author
|
Pushed an update folding learnings from the actual migration (PRs #54722-#54726) into the skill, mirroring dotnet/skills#756:
Once dotnet/skills#756 merges, this branch will be in sync with upstream. |
… equivalence Addresses review comment from copilot-pull-request-reviewer: the Step 6 summary table conflated xUnit's exact-type Assert.IsType<T> and assignable Assert.IsAssignableFrom<T> into a single row, which implies both map interchangeably even though their semantics differ. Split into three rows -- IsType<T> -> IsExactInstanceOfType<T>, IsNotType<T> -> IsNotExactInstanceOfType<T>, IsAssignableFrom<T> -> IsInstanceOfType<T> -- and explicitly call out the silent-weakening trap. The cheatsheet already mapped these correctly; this aligns the SKILL.md summary so the at-a-glance table doesn't suggest a wrong mapping. Mirrored in dotnet/skills#756. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Evangelink
added a commit
to Evangelink/skills
that referenced
this pull request
Jun 11, 2026
… equivalence Address dotnet/sdk#54727 review comment: the Step 6 summary table conflated xUnit's exact-type Assert.IsType<T> and assignable Assert.IsAssignableFrom<T> into a single row, which implies both map interchangeably even though their semantics differ. Split into three rows -- IsType<T> -> IsExactInstanceOfType<T>, IsNotType<T> -> IsNotExactInstanceOfType<T>, IsAssignableFrom<T> -> IsInstanceOfType<T> -- and explicitly call out the silent-weakening trap. The cheatsheet already maps these correctly; this aligns the SKILL.md summary with the cheatsheet so the at-a-glance table doesn't suggest a wrong mapping. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Evangelink
added a commit
to Evangelink/sdk
that referenced
this pull request
Jun 11, 2026
…le(x) Applies the assertion mapping flagged by the migrate-xunit-to-mstest skill (.github/skills/migrate-xunit-to-mstest, PR dotnet#54727). Two occurrences in ParserTests.cs converted from `Assert.HasCount(1, parseResult.Errors)` to the more idiomatic `Assert.ContainsSingle(parseResult.Errors)`, which matches the xUnit original (`Assert.Single`) more directly. Verified: 9/9 tests still pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Evangelink
added a commit
to Evangelink/sdk
that referenced
this pull request
Jun 11, 2026
…tain for strings The migrate-xunit-to-mstest skill (.github/skills/migrate-xunit-to-mstest, PR dotnet#54727) notes that MSTest 3.8+ added Assert.Contains(needle, str) / Assert.DoesNotContain(needle, str) overloads for strings -- with the natural (needle, haystack) argument order matching xUnit's Assert.Contains. With the 4.3.0-preview MSTest.Sdk bump in dotnet#54722, these are now available throughout the migration. Replaced: - StringAssert.Contains(haystack, needle) -> Assert.Contains(needle, haystack) - Assert.IsFalse(haystack.Contains(needle)) -> Assert.DoesNotContain(needle, haystack) Touched files: - BrowserRefreshMiddlewareTest.cs - BrowserScriptMiddlewareTest.cs - ResponseStreamWrapperCompressionTest.cs Note: Assert.IsFalse(dict.ContainsKey(key)) call sites are unchanged (no Assert.DoesNotContainKey API exists). Verified: 110/110 tests still pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Evangelink
added a commit
to dotnet/skills
that referenced
this pull request
Jun 12, 2026
* migrate-xunit-to-mstest: add learnings from dotnet/sdk migration Refines the skill based on a real migration of 5 test projects in dotnet/sdk: - MSTest.Sdk implicit global using: do not add `<Using Include='Microsoft.VisualStudio.TestTools.UnitTesting' />` or per-file `using` in MSTest.Sdk projects (it's already in scope). Note Option A (`MSTest` metapackage) still needs the per-file using. - `Assert.IsExactInstanceOfType<T>` (MSTest 4.1+) is the proper single-call equivalent of xUnit's exact-type `Assert.IsType<T>`; previous guidance silently degraded it to assignable semantics (closes #755). - `Assert.AreSequenceEqual` (MSTest 4.3+) is the modern element-wise equivalent of xUnit's `Assert.Equal` on `IEnumerable<T>`, avoiding the `CollectionAssert` + `.ToList()` dance and the MSTEST0065 trap on plain `AreEqual`. - Clarify `AwesomeAssertions` ships in the `FluentAssertions` namespace, so it's a no-source-change swap. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * SKILL.md: split IsType/IsAssignableFrom row to avoid implying drop-in equivalence Address dotnet/sdk#54727 review comment: the Step 6 summary table conflated xUnit's exact-type Assert.IsType<T> and assignable Assert.IsAssignableFrom<T> into a single row, which implies both map interchangeably even though their semantics differ. Split into three rows -- IsType<T> -> IsExactInstanceOfType<T>, IsNotType<T> -> IsNotExactInstanceOfType<T>, IsAssignableFrom<T> -> IsInstanceOfType<T> -- and explicitly call out the silent-weakening trap. The cheatsheet already maps these correctly; this aligns the SKILL.md summary with the cheatsheet so the at-a-glance table doesn't suggest a wrong mapping. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * SKILL.md: resolve Step 3/Step 4 conflict on the MSTest using for Option B Address review feedback on #756: Step 3 said to skip the per-file 'using Microsoft.VisualStudio.TestTools.UnitTesting;' on Option B (MSTest.Sdk provides it as an implicit global using), but Step 4 unconditionally instructed replacing xUnit usings with that MSTest using -- so an agent following Step 4 literally would re-add the redundant using on Option B projects. Also drop the dangling 'Step 4 rewriter' phrasing in Step 3 (there is no rewriter in Step 4, just a list of mechanical rewrites the agent applies). Step 4 now explicitly says to skip the MSTest using on Option B and only remove the 'using Xunit;' lines, matching Step 2's note and Step 3's branch instructions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Evangelink <amaury@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Imports the migrate-xunit-to-mstest skill from
dotnet/skillsinto this repo so the xUnit → MSTest migration currently in progress (see #54722, #54723, #54724, #54725, #54726) has a documented, repeatable procedure that contributors and agents can follow consistently.What's added
.github/skills/migrate-xunit-to-mstest/SKILL.md— verbatim from upstream.github/skills/migrate-xunit-to-mstest/references/mapping-cheatsheet.md— verbatim from upstreamWhy land this first
These small migration PRs all follow the same mechanical mapping table (
[Fact]→[TestMethod],Assert.Equal→Assert.AreEqual, theAssert.Containsarg-reversal,StringValuesambiguity,Assert.Collectionexpansion, etc.). Centralizing the procedure as a discoverable skill means reviewers and future contributors don't need to rediscover the gotchas from each PR's description.Validator note
.github/skills/ValidateSkill.csflagsSKILL.mdas 546 lines (advisory limit is 500). The validator is not CI-enforced (no workflow consumes it; it's mentioned only as a checklist item in.github/skills/AGENTS.md). I'm intentionally mirroring upstream verbatim so future re-syncs stay trivial. If the team prefers a trimmed copy, happy to fold the longer sections (steps 8, 11, 12) intoreferences/.Source
mainat time of import): https://github.com/dotnet/skills/tree/main/plugins/dotnet-test/skills/migrate-xunit-to-mstest