Skip to content

Migrate Microsoft.DotNet.GenAPI.Tests to MSTest.Sdk on MTP - #54726

Merged
Evangelink merged 36 commits into
dotnet:mainfrom
Evangelink:evangelink/mstest-mtp-genapi-tests
Jun 22, 2026
Merged

Migrate Microsoft.DotNet.GenAPI.Tests to MSTest.Sdk on MTP#54726
Evangelink merged 36 commits into
dotnet:mainfrom
Evangelink:evangelink/mstest-mtp-genapi-tests

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Migrates Microsoft.DotNet.GenAPI.Tests from xUnit v3 to MSTest.Sdk on MTP, continuing the small-PR migration started in #54722.

What changed

Project file (Microsoft.DotNet.GenAPI.Tests.csproj)

  • Switched to Sdk="MSTest.Sdk" with <UseMSTestSdk>true</UseMSTestSdk> (gated in test/Directory.Build.targets from Migrate Microsoft.DotNet.HotReload.Watch.Aspire.Tests to MSTest.Sdk on MTP (pathfinder) #54722)
  • Dropped Microsoft.NET.TestFramework ProjectReference and OutputType=Exe
  • Removed cross-project <Compile Include> of SymbolFactory.cs / TempDirectory.cs (originally pulled from Microsoft.DotNet.ApiSymbolExtensions.Tests) — copied locally and ported the one Assert.Empty call to Assert.IsEmpty. The original copies remain untouched so the still-xUnit ApiSymbolExtensions.Tests project keeps working.

Test sources — mechanical conversion:

  • [Fact]/[Theory][TestMethod]
  • [InlineData(...)][DataRow(...)]
  • [Fact(Skip="…")][TestMethod, Ignore("…")]
  • Added [TestClass] to test classes
  • Assert.Equal/NotEqual/True/False/Null/NotNull/EmptyAreEqual/AreNotEqual/IsTrue/IsFalse/IsNull/IsNotNull/IsEmpty

Verification

total: 109
failed: 0
succeeded: 107
skipped: 2   (pre-existing https://github.com/dotnet/roslyn/issues/74109)

PR stack

Built on top of #54725#54724#54723#54722. Will rebase as the earlier PRs merge.

Copilot AI review requested due to automatic review settings June 11, 2026 19:46
@Evangelink
Evangelink requested review from a team and tmat as code owners June 11, 2026 19:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR continues the repo-wide migration from xUnit v3 to MSTest.Sdk on Microsoft.Testing.Platform (MTP) by converting several test projects (notably Microsoft.DotNet.GenAPI.Tests) to Sdk="MSTest.Sdk" and mechanically updating attributes/asserts to MSTest equivalents.

Changes:

  • Switch multiple test projects to MSTest.Sdk + UseMSTestSdk=true, and gate xUnit-specific defaults in test/Directory.Build.targets.
  • Convert test sources from xUnit [Fact]/[Theory] to MSTest [TestMethod] + [DataRow], updating assertions accordingly.
  • Add/adjust supporting test helpers and references (local helper copies for GenAPI tests, InternalsVisibleTo and project refs for dotnet-watch Aspire integration tests).
Show a summary per file
File Description
test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/Microsoft.DotNet.HotReload.Watch.Aspire.Tests.csproj Switch Aspire unit tests to MSTest.Sdk and update references/usings accordingly.
test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AssertEx.cs Add a small MSTest-friendly helper to replace xUnit-coupled shared helpers.
test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireServerLauncherCliTests.cs Convert xUnit tests to MSTest attributes/assertions.
test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireResourceLauncherCliTests.cs Convert xUnit tests to MSTest, keep FluentAssertions-style checks where used.
test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireHostLauncherTests.cs Convert xUnit tests to MSTest.
test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireHostLauncherCliTests.cs Convert xUnit tests to MSTest.
test/Microsoft.DotNet.GenAPI.Tests/Microsoft.DotNet.GenAPI.Tests.csproj Migrate GenAPI test project to MSTest.Sdk, drop xUnit-coupled test framework reference.
test/Microsoft.DotNet.GenAPI.Tests/CSharpFileBuilderTests.cs Convert large xUnit test suite to MSTest.
test/Microsoft.DotNet.GenAPI.Tests/SyntaxRewriter/TypeDeclarationCSharpSyntaxRewriterTests.cs Convert xUnit tests to MSTest.
test/Microsoft.DotNet.GenAPI.Tests/SyntaxRewriter/SingleLineStatementCSharpSyntaxRewriterTests.cs Convert xUnit tests to MSTest.
test/Microsoft.DotNet.GenAPI.Tests/SyntaxRewriter/CSharpSyntaxRewriterTestBase.cs Update base assertions to MSTest equivalents.
test/Microsoft.DotNet.GenAPI.Tests/SyntaxRewriter/BodyBlockCSharpSyntaxRewriterTests.cs Convert xUnit tests to MSTest.
test/Microsoft.DotNet.GenAPI.Tests/SymbolFactory.cs Copy helper locally and update assertions for MSTest.
test/Microsoft.DotNet.GenAPI.Tests/TempDirectory.cs Copy helper locally for GenAPI tests (replacing cross-project compile includes).
test/Microsoft.DotNet.ApiCompat.Tests/Microsoft.DotNet.ApiCompat.Tests.csproj Switch ApiCompat tests to MSTest.Sdk, drop xUnit-coupled test framework reference.
test/Microsoft.DotNet.ApiCompat.Tests/RegexStringTransformerTests.cs Convert xUnit tests to MSTest.
test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests.csproj Switch BrowserRefresh tests to MSTest.Sdk, drop xUnit-coupled test framework reference.
test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/ScriptInjectingStreamTests.cs Convert xUnit tests to MSTest, update async/cancellation patterns.
test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/ResponseStreamWrapperCompressionTest.cs Convert xUnit tests to MSTest, update string/sequence assertions.
test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/HostingStartupTest.cs Convert xUnit tests to MSTest, adjust header comparisons.
test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/BrowserScriptMiddlewareTest.cs Convert xUnit tests to MSTest; rewrite header assertions without Assert.Collection.
test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/BrowserRefreshMiddlewareTest.cs Convert xUnit [Theory]/[InlineData] to MSTest [DataRow].
test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/BlazorWasmHotReloadMiddlewareTest.cs Convert xUnit tests to MSTest (includes assertion helper logic).
test/dotnet-watch.Tests/dotnet-watch.Tests.csproj Add Watch.Aspire project reference needed by moved Aspire integration tests.
test/dotnet-watch.Tests/Aspire/PipeUtilities.cs Add Aspire integration helper for reading status events over named pipes.
test/dotnet-watch.Tests/Aspire/AspireLauncherIntegrationTests.cs Rename moved integration test class to reflect integration scope.
test/Directory.Build.targets Gate xUnit-specific test defaults behind UseMSTestSdk != true.
test/containerize.UnitTests/containerize.UnitTests.csproj Switch containerize unit tests to MSTest.Sdk and drop xUnit-coupled reference.
test/containerize.UnitTests/ParserTests.cs Convert xUnit tests to MSTest, update assertions/data rows.
src/Dotnet.Watch/Watch.Aspire/Properties/AssemblyInfo.cs Add InternalsVisibleTo for dotnet-watch.Tests.
global.json Add MSTest.Sdk to msbuild-sdks to support the new project SDK usage.

Copilot's findings

  • Files reviewed: 30/31 changed files
  • Comments generated: 2

Comment thread test/Microsoft.DotNet.GenAPI.Tests/TempDirectory.cs
@Evangelink
Evangelink marked this pull request as draft June 11, 2026 19:53
@Evangelink
Evangelink force-pushed the evangelink/mstest-mtp-genapi-tests branch from 545992e to 24ff773 Compare June 11, 2026 20:20
@Evangelink

Copy link
Copy Markdown
Member Author

Re-validated this PR against the new migrate-xunit-to-mstest skill landed in #54727 and bumped MSTest.Sdk to 4.3.0-preview.26311.10 (latest internal preview) via the pathfinder.

Changes applied in the latest push on this branch:
Re-validated; no changes required.

Other gotchas reviewed (no changes needed here):

  • Assert.AreEqual argument order — verified (expected, actual) throughout, matching the xUnit Assert.Equal(expected, actual) original.
  • CollectionAssert argument order — verified.
  • Assert.ThrowsExactly<T> vs Assert.Throws<T> semantics — verified (xUnit Throws<T> is exact; MSTest's same-named API is inclusive, so the migration uses ThrowsExactly<T>).
  • IsInstanceOfType<T> vs IsExactInstanceOfType<T> — see dotnet/skills#755 for the cheatsheet update we filed upstream.

Tests still pass locally on the bumped MSTest.Sdk.

@Evangelink
Evangelink force-pushed the evangelink/mstest-mtp-genapi-tests branch 2 times, most recently from 29c936b to ab88ade Compare June 11, 2026 21:04
Evangelink added a commit that referenced this pull request Jun 12, 2026
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 (#54722,
#54723, #54724, #54725, #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>
@Evangelink

Copy link
Copy Markdown
Member Author

Replaced the manual <UseMSTestSdk>true</UseMSTestSdk> opt-in with the property MSTest.Sdk already sets for us: UsingMSTestSdk. Since MSTest.Sdk's Sdk.props runs before Microsoft.NET.Sdk.props and test/Directory.Build.targets is imported at the bottom of evaluation, the property is in scope wherever we need it — no per-project knob required.

Also refreshed the related comments in XUnitPublish.targets / XUnitRunner.targets and renamed the intermediate _UseMSTestSdk MSBuild property to _UsingMSTestSdk for clarity. (Thanks @Evangelink for the catch.)

@Evangelink
Evangelink force-pushed the evangelink/mstest-mtp-genapi-tests branch from f419649 to 5c37ccc Compare June 12, 2026 11:36
@Evangelink

Copy link
Copy Markdown
Member Author

Made --report-trx conditional on Microsoft.Testing.Extensions.TrxReport actually being loaded. MSTest.Sdk enables that extension by default via EnableMicrosoftTestingExtensionsTrxReport=true for the Default / AllMicrosoft profiles, but other MTP hosts (xUnit v3 MTP, MSTest.Sdk with TestingExtensionsProfile=None, etc.) do not — passing --report-trx there fails with 'unknown argument'.

The new GetTrxReportEnabled target queries that property; XUnitRunner.targets propagates it as EnableTrxReport metadata, and SDKCustomCreateXUnitWorkItemsWithTestExclusion only emits the flag when it's true. No behavioural change for the current PRs since all migrated projects are MSTest.Sdk-based, but the dispatcher is now forward-safe.

(Applied to all 9 stacked PRs since they share these plumbing files.)

@Evangelink

Copy link
Copy Markdown
Member Author

Replaced the custom <UseMSTestSdk> opt-in property with the built-in UsingMSTestSdk property that MSTest.Sdk already sets in its Sdk.props before Directory.Build.props is evaluated. This drops a redundant declaration in every migrated csproj and just reads what the SDK already publishes.

@Evangelink
Evangelink force-pushed the evangelink/mstest-mtp-genapi-tests branch from 5c37ccc to 6371cad Compare June 12, 2026 12:07
@Evangelink

Copy link
Copy Markdown
Member Author

Round 3: moved FluentAssertions Using and AwesomeAssertions PackageReference to test/Directory.Build.targets.

The Using is now global for any test project ('$(IsTestProject)' == 'true' OR '$(UsingMSTestSdk)' == 'true'). The PackageReference is added for MSTest.Sdk projects only — xUnit projects already get it transitively via the Microsoft.NET.TestFramework project reference.

Deviation from your literal suggestion: I left the Microsoft.NET.TestFramework.* Usings and Xunit Using gated on UsingMSTestSdk != true. Moving them unconditional would also require a global <ProjectReference Include="Microsoft.NET.TestFramework" /> (otherwise MSTest projects would fail with CS0246), which would drag xunit.v3.assert and other xUnit pieces into the MSTest projects. Happy to apply the broader change (with a global ProjectRef) if you'd prefer.

Evangelink and others added 6 commits June 12, 2026 18:03
…n MTP

This is a pathfinder PR for migrating the test suite to MSTest on
Microsoft.Testing.Platform (MTP). Microsoft.DotNet.HotReload.Watch.Aspire.Tests
was chosen because it has no dependency on the shared Microsoft.NET.TestFramework
(which is xUnit-coupled and referenced by ~57 of 78 test projects), so it can
migrate in isolation without unblocking dependents first.

Changes:

* global.json: add MSTest.Sdk 4.3.0-preview.26307.5 to msbuild-sdks.
* test/Directory.Build.targets: gate the xUnit defaults
  (TestRunnerName=XUnitV3, Using Include=Xunit, etc.) behind
  $(UseMSTestSdk) != true, so MSTest.Sdk projects opt out cleanly.
* test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests:
  - csproj now uses Sdk="MSTest.Sdk", sets UseMSTestSdk=true, references
    AwesomeAssertions and only the Watch.Aspire project. MTP is on by default
    via MSTest.Sdk (EnableMSTestRunner + TestingPlatformDotnetTestSupport).
  - All 4 unit-test files converted from xUnit to MSTest attributes/asserts
    ([Fact]/[Theory] -> [TestMethod]/[DataRow], Assert.* equivalents,
    Assert.IsInstanceOfType<T>, Assert.HasCount, Assert.IsEmpty).
  - Local AssertEx.SequenceEqual<T> helper replaces the xUnit-coupled one
    from HotReload.Test.Utilities.
* Move the 2 integration tests (AspireLauncherTests + PipeUtilities) to
  test/dotnet-watch.Tests/Aspire/ so the Aspire.Tests project stays a pure
  MSTest unit-test project. They keep xUnit because they depend on
  WatchSdkTest, WatchableApp, [PlatformSpecificFact], ITestOutputHelper and
  TestAssets from Microsoft.NET.TestFramework. AspireLauncherTests was
  renamed to AspireLauncherIntegrationTests to reflect its new role.
* src/Dotnet.Watch/Watch.Aspire/Properties/AssemblyInfo.cs: grant
  InternalsVisibleTo to dotnet-watch.Tests (needed by PipeUtilities, which
  uses internal WatchStatusEvent).
* test/dotnet-watch.Tests/dotnet-watch.Tests.csproj: add ProjectReference to
  Watch.Aspire (ExcludeAssets=Runtime) so the moved integration tests
  compile.

Verification:
* Microsoft.DotNet.HotReload.Watch.Aspire.Tests builds with MSTest.Sdk and
  all 58 unit tests pass under MTP (705 ms).
* test/dotnet-watch.Tests builds successfully with the moved files.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- 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>
…parity

Per reviewer feedback: MSTest 4.1.0+ exposes Assert.IsExactInstanceOfType<T>(value)
which returns T and enforces exact-type semantics -- the proper equivalent
of xUnit's Assert.IsType<T>(x). Assert.IsInstanceOfType<T> is the equivalent
of xUnit's Assert.IsAssignableFrom<T> (assignable, not exact), which would
be a silent semantic regression for the IsType<T> originals.

All 39 occurrences across AspireHostLauncherCliTests.cs,
AspireResourceLauncherCliTests.cs, AspireServerLauncherCliTests.cs, and
AspireLauncherIntegrationTests.cs were originally Assert.IsType<T> in
xUnit (verified against main), so all 39 are flipped to
Assert.IsExactInstanceOfType<T>.

Note: the migrate-xunit-to-mstest skill cheatsheet at
.github/skills/migrate-xunit-to-mstest/references/mapping-cheatsheet.md
recommends `Assert.IsInstanceOfType<T>` plus an extra typeof-check for
exact-type semantics; that guidance predates IsExactInstanceOfType being
available. Follow-up upstream (dotnet/skills) suggested.

Verified: 58/58 Aspire tests still pass; dotnet-watch.Tests builds clean.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
MSTest.Sdk already adds this as an implicit global using.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
MSTest 4.3+ provides Assert.AreSequenceEqual for element-wise IEnumerable<T> compare with a nice diff message, so the project-local AssertEx helper is no longer needed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…est/Directory.Build.targets

Per @Evangelink: keep per-csproj boilerplate minimal. FluentAssertions is now a
global using for any test project (gated on IsTestProject OR UsingMSTestSdk),
and AwesomeAssertions is added as a PackageReference for MSTest.Sdk projects.
xUnit projects continue to pick it up transitively via Microsoft.NET.TestFramework.

The Microsoft.NET.TestFramework.* and Xunit usings remain gated on the xUnit
branch (UsingMSTestSdk != true) because MSTest projects in this repo do not
reference Microsoft.NET.TestFramework; making those usings global would fail
with CS0246.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

AspireLauncherIntegrationTests exec the Aspire launcher (Microsoft.DotNet.HotReload.Watch.Aspire)
as a child process. ExcludeAssets=Runtime omitted the launcher's transitive runtime dependencies
(Microsoft.CodeAnalysis*) from the test output, so the launched process crashed at startup with
FileNotFoundException and the tests failed with Assert.NotNull. Removing ExcludeAssets=Runtime
deploys the full closure next to the launcher.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink

Copy link
Copy Markdown
Member Author

/azp run dotnet-sdk-public-ci

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink

Copy link
Copy Markdown
Member Author

Addressed the GenAPI helper namespace feedback: moved the copied TempDirectory and SymbolFactory helpers into the Microsoft.DotNet.GenAPI.Tests namespace and removed the now-unneeded foreign test namespace usings. Commit: 3660cfc

Evangelink and others added 3 commits June 17, 2026 09:10
…tionTests)

PR dotnet#54766 enabled the Recommended MSTest analyzers as errors; dotnet#54758 merged shortly
after with violations that are now build errors, leaving main red and blocking all
open migration PRs. Fix the two affected files:
- CommandResultAssertions.MSTest.cs: MSTEST0037 (IsTrue(a==b)->AreEqual, IsFalse(a==b)
  ->AreNotEqual) and MSTEST0023 (IsTrue(!x)->IsFalse(x)).
- LocalizeTemplateTests.cs: MSTEST0037 (AreEqual(n, x.Length)->HasCount(n, x)).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
(cherry picked from commit 6ac4ef0)
…stacked genapi PR

Imports the already-verified analyzer fixes for the stale lower-stack copies. Note:
a separate CS0305 in TestAssemblyLoaderFactory.cs (SymbolFactory<,> collision when
cross-compiled into ApiDiff.Tests) still needs investigation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The shared helpers (SymbolFactory, TempDirectory, TestAssemblyLoaderFactory)
are cross-linked into Microsoft.DotNet.ApiDiff.Tests, which also links
SymbolFactory from Microsoft.DotNet.ApiSymbolExtensions.Tests. Moving them to
the GenAPI.Tests namespace breaks SymbolFactory resolution in that
cross-compilation (CS0305). Keep them in the ApiSymbolExtensions.Tests
namespace.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink
Evangelink enabled auto-merge (squash) June 17, 2026 11:13
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink

Copy link
Copy Markdown
Member Author

/ba-g #54914

@Evangelink
Evangelink merged commit 8af14ee into dotnet:main Jun 22, 2026
24 of 26 checks passed
@dotnet-milestone-bot dotnet-milestone-bot Bot added this to the 11.0-preview6 milestone Jun 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants