Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path) - #9706

Merged
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest
Jul 8, 2026
Merged

Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path)#9706
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest

Conversation

@Evangelink

@EvangelinkAmaury Levé (Evangelink) commented Jul 7, 2026

Copy link
Copy Markdown
Member

What

Works toward removing the Microsoft.Testing.Extensions.VSTestBridge dependency from MSTest's Microsoft.Testing.Platform (MTP) code path, so MSTest plugs into MTP natively. Delivered as a reviewable, phased series — all behind the opt-in MSTEST_EXPERIMENTAL_NATIVE_MTP switch, so the shipping default (the bridge) is unchanged.

  • RFC 018 — the roadmap/design (docs/RFCs/018-...md).
  • Phase 1 — native TestNode production seam (MSTestTestNodeConverter, MtpUnitTestElementSink, MtpTestResultRecorder).
  • Phase 2 — proved the seams by wiring them behind the flag (now superseded by the native framework).
  • Phases 3–5 — a native MSTestTestFramework that handles the MTP request directly: native filtering, runsettings/config, message logging, and session lifecycle. No VSTest bridge object-model adapters on the native request path.
  • Review feedback addressed (async neutral seams, UTF-8 BOM, doc style).

Why

On the MTP path, MSTest round-trips through the VSTest object model (context/filter/runsettings/handle/sink adapters) even though its engine already runs on neutral models. Going native removes that plumbing.

Phases 3–5 in the latest commit

A native MSTestTestFramework : ITestFramework, IDataProducer replaces the bridge framework on the flag path and reuses MSTest's existing MSTestDiscoverer/MSTestExecutor engine. New (all #if !WINDOWS_UWP):

  • MSTestFilterContext (MSTestRunContext/MSTestDiscoveryContext) — native IRunContext/IDiscoveryContext that builds the VSTest ITestCaseFilterExpression from the MTP ITestExecutionFilter + --filter + runsettings <TestCaseFilter> (reusing Microsoft.TestPlatform.Filter.Source, now referenced directly). MSTest's existing TestMethodFilter matching is unchanged.
  • MSTestRunSettings — native IRunSettings: reads runsettings, patches MTP defaults (DesignMode/ResultsDirectory/--test-parameter), and warns on unsupported entries (reusing the bridge's already-localized ExtensionResources).
  • MSTestFrameworkHandle — an IFrameworkHandle that only forwards messages to IOutputDevice (results flow through the native recorder).
  • AddMSTest branches the framework factory on the flag; the bridge's shared command-line/config/env-var registrations are kept for now (retired with the dependency in the final step).

Validation

  • Full .\build.cmd — 0 warnings, 0 errors across all TFMs.
  • Unit tests: 45 (MSTestAdapter.UnitTests) + 898 (MSTestAdapter.PlatformServices.UnitTests), all green.
  • Native path (flag on, acceptance):185 tests green — FilterTests, RunsettingsTests (incl. localization), OutputTests, TrxReportTests, ThreadingTests (STA), ServerModeTests, DeploymentItem, DataSourceTests, Inconclusive/Ignore, TestRunParameters, TimeoutTests.
  • Default bridge path (flag off, acceptance):FilterTests + RunsettingsTests (45) — unchanged.

Remaining — Phase 6 (separate, gated)

Flip the default to native and drop the VSTestBridge dependency from MSTest. This is gated on:

  1. Full MSTest acceptance-suite parity on the native path (hundreds of tests — needs CI).
  2. Native replacements for the bridge's remaining shared registrations (the --filter/--settings/--test-parameter option providers and the runsettings config/env-var providers), so the package reference can be removed.

The bridge package itself is not removed — NUnit/Expecto/3rd-party adapters still use it. Only MSTest stops depending on it.

…bridge)
Proposes a staged roadmap to plug MSTest directly into Microsoft.Testing.Platform as a native ITestFramework, replacing the Microsoft.Testing.Extensions.VSTestBridge indirection on the MTP code path. Documents the existing neutral seams (IUnitTestElementSink, ITestResultRecorder, IAdapterMessageLogger, ITestElementFilterProvider, DeploymentContext), a 6-phase plan, capability parity checklist, testing strategy, and risks.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 7, 2026 12:48

CopilotAI 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 adds RFC 018, a design/roadmap document proposing that MSTest plug directly into Microsoft.Testing.Platform (MTP) as a first-class ITestFramework, retiring the Microsoft.Testing.Extensions.VSTestBridge indirection on the MTP code path. It is a documentation-only artifact (status "Under discussion") with no production code changes, intended to let maintainers steer the approach before implementation. The RFC documents the current double-conversion architecture, the existing neutral seams the engine already uses, a 6-phase independently-shippable roadmap, a capability/feature-parity checklist, and the testing strategy, risks, and open questions.

Changes:

  • Documents current vs. target MTP architecture, highlighting the wasteful neutral model → VSTest TestCase/TestResult → TestNode double conversion and the resulting information loss (empty AssemblyFullName/ReturnTypeFullName).
  • Lays out a 6-phase roadmap that keeps the bridge as default until the native path reaches parity, with a feature-parity checklist and dual-run testing strategy.
  • Follows the established docs/RFCs/ convention; the bridge package is not removed (NUnit/Expecto/third-party adapters still use it) — only MSTest stops depending on it.
Show a summary per file
FileDescription
docs/RFCs/018-Native-MTP-Integration-For-MSTest.mdNew RFC describing the native MTP integration design, phasing, parity checklist, testing strategy, risks, and open questions. All referenced types, seams, file paths, and the quoted in-code comment were verified as accurate against the codebase.

Review details

  • Files reviewed: 1/1 changed files
  • Comments generated: 0
  • Review effort level: Medium

@github-actionsgithub-actionsBot 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.

Note

🤖 Automated review by GitHub Copilot. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

#DimensionVerdict
17Documentation Accuracy🟢 2 NIT
21Scope & PR Discipline🟢 1 NIT

✅ 20/22 dimensions N/A (no code changes). 2 dimensions reviewed — only minor nits found.

Summary: This is a well-structured, thoroughly researched RFC. The claims about existing neutral seams (IUnitTestElementSink, ITestResultRecorder, IAdapterMessageLogger, ITestElementFilterProvider) are verified against the codebase, the MSTestBridgedTestFramework information-loss quote is accurate (line 100–106 in that file), and the 6-phase roadmap with the capability parity checklist covers all bridge features I can identify. The design principle of "boundary replacement, not engine rewrite" is well-supported by the architecture diagrams.

  • Path convention: use forward slashes for cross-platform consistency (line 84)
  • Consider linking a tracking issue for the 6-phase roadmap

Comment threaddocs/RFCs/018-Native-MTP-Integration-For-MSTest.md Outdated
Comment threaddocs/RFCs/018-Native-MTP-Integration-For-MSTest.md
Adds the first, unwired building block for plugging MSTest directly into Microsoft.Testing.Platform instead of routing through the VSTest bridge:
- MSTestTestNodeConverter: builds MTP TestNodes directly from MSTest's neutral models (UnitTestElement + framework TestResult), faithfully porting the mapping the bridge does today via ObjectModelConverters/TestResultExtensions/UnitTestElementExtensions (outcome, timing, std out/err, TRX categories/messages/exception/type-name, traits, file location, TestMethodIdentifierProperty).
- MtpUnitTestElementSink / MtpTestResultRecorder: MTP-native IUnitTestElementSink / ITestResultRecorder that publish TestNodeUpdateMessage on the message bus.
- MSTestTestNodeException: native message+stacktrace carrier (replaces the bridge's VSTestException on the MSTest path).
- UnitTestElementExtensions.GetTestId: exposes the stable test id neutrally, without materializing a VSTest TestCase.
The bridge remains the default; these seams are covered by 24 unit tests and are wired in a later phase. No behavior change.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@EvangelinkAmaury Levé (Evangelink) changed the title docs: RFC 018 — native MTP integration for MSTest (retire the VSTest bridge)Native MTP integration for MSTest — RFC 018 + Phase 1 (TestNode production seam)Jul 7, 2026
@github-actions

This comment has been minimized.

When the MSTEST_EXPERIMENTAL_NATIVE_MTP opt-in is set, MSTest publishes discovery and result TestNodes directly via the Phase 1 native converter+seams, bypassing the bridge's ObjectModelConverters / FrameworkHandlerAdapter / TestCaseDiscoverySinkAdapter. The bridge remains the default; only context/filter/config/command-line parsing still flows through it.
Changes:
- VSTestBridge base: expose the session UID as an internal auto-property (bridge already has InternalsVisibleTo MSTest.TestAdapter; no public API change).
- MSTestDiscoverer: add an IUnitTestElementSink overload and share a discovery core so the native sink is used directly instead of discoverySink.ToUnitTestElementSink().
- MSTestExecutor: add a Func<MSTestSettings,ITestResultRecorder> overload and share a run core so a native recorder is used instead of frameworkHandle.ToTestResultRecorder(); the framework handle is still used for message logging and apartment-state handling.
- MSTestBridgedTestFramework: flag-gated native wiring.
Validated: full build 0/0; MSTestAdapter.UnitTests 45/45; native-path acceptance OutputTests(6)+TrxReportTests(3)+Inconclusive/Ignore/DataSource(38) all green; default bridge-path OutputTests(6) unchanged.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 7, 2026 14:04
@EvangelinkAmaury Levé (Evangelink) changed the title Native MTP integration for MSTest — RFC 018 + Phase 1 (TestNode production seam)Native MTP integration for MSTest — RFC 018 + Phase 1 & 2 (opt-in native TestNode path)Jul 7, 2026

CopilotAI 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.

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 5
  • Review effort level: Medium

Comment threadtest/UnitTests/MSTestAdapter.UnitTests/MSTestTestNodeConverterTests.cs Outdated
@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test quality grade — PR #9706

24 new test methods in MSTestTestNodeConverterTests cover MSTestTestNodeConverter, MtpUnitTestElementSink, and MtpTestResultRecorder. All 24 earn A (90–100): clear Arrange-Act-Assert structure, focused single-behavior design, and rich AwesomeAssertions throughout. Two minor opportunities: some tests pass DateTimeOffset.Now as a non-timing parameter (a named constant would be cleaner), and one negative test omits an absence assertion for symmetry with its enabled counterpart.

GradeTestNotes
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordEmptyResult_
PublishesNothing
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordResult_
PublishesResultNodeAndReturnsFailedFlag
Tests both return value and published state; consider splitting into two focused tests for sharper isolation.
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordResult_
ReturnsFalse_
ForPassedTest
Return value correctly checked; consider also asserting the published node carries PassedTestNodeStateProperty for symmetry.
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordStart_
PublishesInProgressNode
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
MtpUnitTestElementSink_
PublishesDiscoveredTestNode
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsCategoriesAndTraitsAsMetadata
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsFileLocation_
WhenDeclaringFileKnown
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsTestMethodIdentifier_
FromManagedNames
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsTrxCategories_
OnlyWhenTrxEnabled
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
DoesNotAddFileLocation_
WhenDeclaringFileUnknown
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
DoesNotAddTestMethodIdentifier_
WhenNoManagedMethodName
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
SetsUidDisplayNameAndDiscoveredState
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
UsesExplicitDisplayName_
WhenProvided
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToInProgressTestNode_
AddsInProgressState
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
AddsTimingProperty
Uses explicit deterministic timestamps; duration equality verified — no issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
AddsTrxProperties_
WhenTrxEnabled
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
DoesNotAddTrxProperties_
WhenTrxDisabled
Consider also asserting TrxFullyQualifiedTypeNameProperty absence for symmetry with the enabled test.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
IncludesDebugTraceAndTestContextBannersInStandardOutput
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsFailedOutcome_
WithMessageAndStackTrace
Both exception fields verified; replace DateTimeOffset.Now in non-timing args with a fixed constant for clarity.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsIgnoredOutcomeToSkipped
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsInconclusiveToSkipped_
ByDefault
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsLogOutputAndLogErrorToStandardStreams
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsNotFoundOutcomeToError
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsPassedOutcome
No issues found.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Generated by the Grade Tests on PR (on open / sync) workflow. · 145.8 AIC · ⌖ 10.8 AIC · ⊞ 9.5K · [◷]( · )

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jul 7, 2026
- Make the neutral discovery/result seams asynchronous end-to-end (per review): ITestResultRecorder (RecordStartAsync/RecordEmptyResultAsync/RecordResultAsync) and IUnitTestElementSink (SendTestElementAsync). Thread async through UnitTestDiscoverer (DiscoverTestsAsync/DiscoverTestsInSourceAsync/SendTestCasesAsync) and TestExecutionManager.SendTestResultsAsync. The MTP implementations now await the message-bus publish instead of blocking with GetAwaiter().GetResult(); the VSTest implementations return completed tasks (sync fast-path preserves STA behavior).
- Add the UTF-8 BOM required by .editorconfig to the five new .cs files.
- Use forward slashes for the seam path in RFC 018.
Validated: full build 0/0; unit tests MSTestAdapter.UnitTests 45/45 and MSTestAdapter.PlatformServices.UnitTests 898/898; acceptance default-path threading/output/trx 41 green; native-path threading/output/trx/outcome/data-driven 75 green.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@Evangelink
Amaury Levé (Evangelink) enabled auto-merge (squash) July 8, 2026 10:16
@Evangelink
Amaury Levé (Evangelink) merged commit 641c192 into mainJul 8, 2026
101 of 102 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/remove-vstest-bridge-mstest branch July 8, 2026 12:02
github-actionsBot added a commit that referenced this pull request Jul 8, 2026
Apply two project-convention improvements to files added in recent PRs:
- MSTestTestNodeConverter.cs (added in #9706): replace Substring calls
with range operators per csharp_style_prefer_range_operator = true
- TestMethodRunner.DataSource.cs (added in #9729): replace == null with
is null per the project's 'always use is null / is not null' rule
No behavioral change; builds verified to succeed with 0 errors.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@EvangelinkAmaury Levé (Evangelink) changed the title Native MTP integration for MSTest — RFC 018 + Phase 1 & 2 (opt-in native TestNode path)Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path)Jul 8, 2026
github-actionsBot added a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Amaury Levé (Evangelink) pushed a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-reviewAwaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Evangelink@0101
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path) - #9706

Merged
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest
Jul 8, 2026
Merged

Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path)#9706
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest

Conversation

@Evangelink

@EvangelinkAmaury Levé (Evangelink) commented Jul 7, 2026

Copy link
Copy Markdown
Member

What

Works toward removing the Microsoft.Testing.Extensions.VSTestBridge dependency from MSTest's Microsoft.Testing.Platform (MTP) code path, so MSTest plugs into MTP natively. Delivered as a reviewable, phased series — all behind the opt-in MSTEST_EXPERIMENTAL_NATIVE_MTP switch, so the shipping default (the bridge) is unchanged.

  • RFC 018 — the roadmap/design (docs/RFCs/018-...md).
  • Phase 1 — native TestNode production seam (MSTestTestNodeConverter, MtpUnitTestElementSink, MtpTestResultRecorder).
  • Phase 2 — proved the seams by wiring them behind the flag (now superseded by the native framework).
  • Phases 3–5 — a native MSTestTestFramework that handles the MTP request directly: native filtering, runsettings/config, message logging, and session lifecycle. No VSTest bridge object-model adapters on the native request path.
  • Review feedback addressed (async neutral seams, UTF-8 BOM, doc style).

Why

On the MTP path, MSTest round-trips through the VSTest object model (context/filter/runsettings/handle/sink adapters) even though its engine already runs on neutral models. Going native removes that plumbing.

Phases 3–5 in the latest commit

A native MSTestTestFramework : ITestFramework, IDataProducer replaces the bridge framework on the flag path and reuses MSTest's existing MSTestDiscoverer/MSTestExecutor engine. New (all #if !WINDOWS_UWP):

  • MSTestFilterContext (MSTestRunContext/MSTestDiscoveryContext) — native IRunContext/IDiscoveryContext that builds the VSTest ITestCaseFilterExpression from the MTP ITestExecutionFilter + --filter + runsettings <TestCaseFilter> (reusing Microsoft.TestPlatform.Filter.Source, now referenced directly). MSTest's existing TestMethodFilter matching is unchanged.
  • MSTestRunSettings — native IRunSettings: reads runsettings, patches MTP defaults (DesignMode/ResultsDirectory/--test-parameter), and warns on unsupported entries (reusing the bridge's already-localized ExtensionResources).
  • MSTestFrameworkHandle — an IFrameworkHandle that only forwards messages to IOutputDevice (results flow through the native recorder).
  • AddMSTest branches the framework factory on the flag; the bridge's shared command-line/config/env-var registrations are kept for now (retired with the dependency in the final step).

Validation

  • Full .\build.cmd — 0 warnings, 0 errors across all TFMs.
  • Unit tests: 45 (MSTestAdapter.UnitTests) + 898 (MSTestAdapter.PlatformServices.UnitTests), all green.
  • Native path (flag on, acceptance):185 tests green — FilterTests, RunsettingsTests (incl. localization), OutputTests, TrxReportTests, ThreadingTests (STA), ServerModeTests, DeploymentItem, DataSourceTests, Inconclusive/Ignore, TestRunParameters, TimeoutTests.
  • Default bridge path (flag off, acceptance):FilterTests + RunsettingsTests (45) — unchanged.

Remaining — Phase 6 (separate, gated)

Flip the default to native and drop the VSTestBridge dependency from MSTest. This is gated on:

  1. Full MSTest acceptance-suite parity on the native path (hundreds of tests — needs CI).
  2. Native replacements for the bridge's remaining shared registrations (the --filter/--settings/--test-parameter option providers and the runsettings config/env-var providers), so the package reference can be removed.

The bridge package itself is not removed — NUnit/Expecto/3rd-party adapters still use it. Only MSTest stops depending on it.

…bridge)
Proposes a staged roadmap to plug MSTest directly into Microsoft.Testing.Platform as a native ITestFramework, replacing the Microsoft.Testing.Extensions.VSTestBridge indirection on the MTP code path. Documents the existing neutral seams (IUnitTestElementSink, ITestResultRecorder, IAdapterMessageLogger, ITestElementFilterProvider, DeploymentContext), a 6-phase plan, capability parity checklist, testing strategy, and risks.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 7, 2026 12:48

CopilotAI 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 adds RFC 018, a design/roadmap document proposing that MSTest plug directly into Microsoft.Testing.Platform (MTP) as a first-class ITestFramework, retiring the Microsoft.Testing.Extensions.VSTestBridge indirection on the MTP code path. It is a documentation-only artifact (status "Under discussion") with no production code changes, intended to let maintainers steer the approach before implementation. The RFC documents the current double-conversion architecture, the existing neutral seams the engine already uses, a 6-phase independently-shippable roadmap, a capability/feature-parity checklist, and the testing strategy, risks, and open questions.

Changes:

  • Documents current vs. target MTP architecture, highlighting the wasteful neutral model → VSTest TestCase/TestResult → TestNode double conversion and the resulting information loss (empty AssemblyFullName/ReturnTypeFullName).
  • Lays out a 6-phase roadmap that keeps the bridge as default until the native path reaches parity, with a feature-parity checklist and dual-run testing strategy.
  • Follows the established docs/RFCs/ convention; the bridge package is not removed (NUnit/Expecto/third-party adapters still use it) — only MSTest stops depending on it.
Show a summary per file
FileDescription
docs/RFCs/018-Native-MTP-Integration-For-MSTest.mdNew RFC describing the native MTP integration design, phasing, parity checklist, testing strategy, risks, and open questions. All referenced types, seams, file paths, and the quoted in-code comment were verified as accurate against the codebase.

Review details

  • Files reviewed: 1/1 changed files
  • Comments generated: 0
  • Review effort level: Medium

@github-actionsgithub-actionsBot 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.

Note

🤖 Automated review by GitHub Copilot. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

#DimensionVerdict
17Documentation Accuracy🟢 2 NIT
21Scope & PR Discipline🟢 1 NIT

✅ 20/22 dimensions N/A (no code changes). 2 dimensions reviewed — only minor nits found.

Summary: This is a well-structured, thoroughly researched RFC. The claims about existing neutral seams (IUnitTestElementSink, ITestResultRecorder, IAdapterMessageLogger, ITestElementFilterProvider) are verified against the codebase, the MSTestBridgedTestFramework information-loss quote is accurate (line 100–106 in that file), and the 6-phase roadmap with the capability parity checklist covers all bridge features I can identify. The design principle of "boundary replacement, not engine rewrite" is well-supported by the architecture diagrams.

  • Path convention: use forward slashes for cross-platform consistency (line 84)
  • Consider linking a tracking issue for the 6-phase roadmap

Comment threaddocs/RFCs/018-Native-MTP-Integration-For-MSTest.md Outdated
Comment threaddocs/RFCs/018-Native-MTP-Integration-For-MSTest.md
Adds the first, unwired building block for plugging MSTest directly into Microsoft.Testing.Platform instead of routing through the VSTest bridge:
- MSTestTestNodeConverter: builds MTP TestNodes directly from MSTest's neutral models (UnitTestElement + framework TestResult), faithfully porting the mapping the bridge does today via ObjectModelConverters/TestResultExtensions/UnitTestElementExtensions (outcome, timing, std out/err, TRX categories/messages/exception/type-name, traits, file location, TestMethodIdentifierProperty).
- MtpUnitTestElementSink / MtpTestResultRecorder: MTP-native IUnitTestElementSink / ITestResultRecorder that publish TestNodeUpdateMessage on the message bus.
- MSTestTestNodeException: native message+stacktrace carrier (replaces the bridge's VSTestException on the MSTest path).
- UnitTestElementExtensions.GetTestId: exposes the stable test id neutrally, without materializing a VSTest TestCase.
The bridge remains the default; these seams are covered by 24 unit tests and are wired in a later phase. No behavior change.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@EvangelinkAmaury Levé (Evangelink) changed the title docs: RFC 018 — native MTP integration for MSTest (retire the VSTest bridge)Native MTP integration for MSTest — RFC 018 + Phase 1 (TestNode production seam)Jul 7, 2026
@github-actions

This comment has been minimized.

When the MSTEST_EXPERIMENTAL_NATIVE_MTP opt-in is set, MSTest publishes discovery and result TestNodes directly via the Phase 1 native converter+seams, bypassing the bridge's ObjectModelConverters / FrameworkHandlerAdapter / TestCaseDiscoverySinkAdapter. The bridge remains the default; only context/filter/config/command-line parsing still flows through it.
Changes:
- VSTestBridge base: expose the session UID as an internal auto-property (bridge already has InternalsVisibleTo MSTest.TestAdapter; no public API change).
- MSTestDiscoverer: add an IUnitTestElementSink overload and share a discovery core so the native sink is used directly instead of discoverySink.ToUnitTestElementSink().
- MSTestExecutor: add a Func<MSTestSettings,ITestResultRecorder> overload and share a run core so a native recorder is used instead of frameworkHandle.ToTestResultRecorder(); the framework handle is still used for message logging and apartment-state handling.
- MSTestBridgedTestFramework: flag-gated native wiring.
Validated: full build 0/0; MSTestAdapter.UnitTests 45/45; native-path acceptance OutputTests(6)+TrxReportTests(3)+Inconclusive/Ignore/DataSource(38) all green; default bridge-path OutputTests(6) unchanged.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 7, 2026 14:04
@EvangelinkAmaury Levé (Evangelink) changed the title Native MTP integration for MSTest — RFC 018 + Phase 1 (TestNode production seam)Native MTP integration for MSTest — RFC 018 + Phase 1 & 2 (opt-in native TestNode path)Jul 7, 2026

CopilotAI 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.

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 5
  • Review effort level: Medium

Comment threadtest/UnitTests/MSTestAdapter.UnitTests/MSTestTestNodeConverterTests.cs Outdated
@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test quality grade — PR #9706

24 new test methods in MSTestTestNodeConverterTests cover MSTestTestNodeConverter, MtpUnitTestElementSink, and MtpTestResultRecorder. All 24 earn A (90–100): clear Arrange-Act-Assert structure, focused single-behavior design, and rich AwesomeAssertions throughout. Two minor opportunities: some tests pass DateTimeOffset.Now as a non-timing parameter (a named constant would be cleaner), and one negative test omits an absence assertion for symmetry with its enabled counterpart.

GradeTestNotes
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordEmptyResult_
PublishesNothing
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordResult_
PublishesResultNodeAndReturnsFailedFlag
Tests both return value and published state; consider splitting into two focused tests for sharper isolation.
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordResult_
ReturnsFalse_
ForPassedTest
Return value correctly checked; consider also asserting the published node carries PassedTestNodeStateProperty for symmetry.
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordStart_
PublishesInProgressNode
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
MtpUnitTestElementSink_
PublishesDiscoveredTestNode
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsCategoriesAndTraitsAsMetadata
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsFileLocation_
WhenDeclaringFileKnown
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsTestMethodIdentifier_
FromManagedNames
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsTrxCategories_
OnlyWhenTrxEnabled
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
DoesNotAddFileLocation_
WhenDeclaringFileUnknown
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
DoesNotAddTestMethodIdentifier_
WhenNoManagedMethodName
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
SetsUidDisplayNameAndDiscoveredState
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
UsesExplicitDisplayName_
WhenProvided
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToInProgressTestNode_
AddsInProgressState
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
AddsTimingProperty
Uses explicit deterministic timestamps; duration equality verified — no issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
AddsTrxProperties_
WhenTrxEnabled
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
DoesNotAddTrxProperties_
WhenTrxDisabled
Consider also asserting TrxFullyQualifiedTypeNameProperty absence for symmetry with the enabled test.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
IncludesDebugTraceAndTestContextBannersInStandardOutput
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsFailedOutcome_
WithMessageAndStackTrace
Both exception fields verified; replace DateTimeOffset.Now in non-timing args with a fixed constant for clarity.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsIgnoredOutcomeToSkipped
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsInconclusiveToSkipped_
ByDefault
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsLogOutputAndLogErrorToStandardStreams
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsNotFoundOutcomeToError
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsPassedOutcome
No issues found.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Generated by the Grade Tests on PR (on open / sync) workflow. · 145.8 AIC · ⌖ 10.8 AIC · ⊞ 9.5K · [◷]( · )

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jul 7, 2026
- Make the neutral discovery/result seams asynchronous end-to-end (per review): ITestResultRecorder (RecordStartAsync/RecordEmptyResultAsync/RecordResultAsync) and IUnitTestElementSink (SendTestElementAsync). Thread async through UnitTestDiscoverer (DiscoverTestsAsync/DiscoverTestsInSourceAsync/SendTestCasesAsync) and TestExecutionManager.SendTestResultsAsync. The MTP implementations now await the message-bus publish instead of blocking with GetAwaiter().GetResult(); the VSTest implementations return completed tasks (sync fast-path preserves STA behavior).
- Add the UTF-8 BOM required by .editorconfig to the five new .cs files.
- Use forward slashes for the seam path in RFC 018.
Validated: full build 0/0; unit tests MSTestAdapter.UnitTests 45/45 and MSTestAdapter.PlatformServices.UnitTests 898/898; acceptance default-path threading/output/trx 41 green; native-path threading/output/trx/outcome/data-driven 75 green.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@Evangelink
Amaury Levé (Evangelink) enabled auto-merge (squash) July 8, 2026 10:16
@Evangelink
Amaury Levé (Evangelink) merged commit 641c192 into mainJul 8, 2026
101 of 102 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/remove-vstest-bridge-mstest branch July 8, 2026 12:02
github-actionsBot added a commit that referenced this pull request Jul 8, 2026
Apply two project-convention improvements to files added in recent PRs:
- MSTestTestNodeConverter.cs (added in #9706): replace Substring calls
with range operators per csharp_style_prefer_range_operator = true
- TestMethodRunner.DataSource.cs (added in #9729): replace == null with
is null per the project's 'always use is null / is not null' rule
No behavioral change; builds verified to succeed with 0 errors.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@EvangelinkAmaury Levé (Evangelink) changed the title Native MTP integration for MSTest — RFC 018 + Phase 1 & 2 (opt-in native TestNode path)Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path)Jul 8, 2026
github-actionsBot added a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Amaury Levé (Evangelink) pushed a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-reviewAwaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Evangelink@0101
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path) - #9706

Merged
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest
Jul 8, 2026
Merged

Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path)#9706
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest

Conversation

@Evangelink

@EvangelinkAmaury Levé (Evangelink) commented Jul 7, 2026

Copy link
Copy Markdown
Member

What

Works toward removing the Microsoft.Testing.Extensions.VSTestBridge dependency from MSTest's Microsoft.Testing.Platform (MTP) code path, so MSTest plugs into MTP natively. Delivered as a reviewable, phased series — all behind the opt-in MSTEST_EXPERIMENTAL_NATIVE_MTP switch, so the shipping default (the bridge) is unchanged.

  • RFC 018 — the roadmap/design (docs/RFCs/018-...md).
  • Phase 1 — native TestNode production seam (MSTestTestNodeConverter, MtpUnitTestElementSink, MtpTestResultRecorder).
  • Phase 2 — proved the seams by wiring them behind the flag (now superseded by the native framework).
  • Phases 3–5 — a native MSTestTestFramework that handles the MTP request directly: native filtering, runsettings/config, message logging, and session lifecycle. No VSTest bridge object-model adapters on the native request path.
  • Review feedback addressed (async neutral seams, UTF-8 BOM, doc style).

Why

On the MTP path, MSTest round-trips through the VSTest object model (context/filter/runsettings/handle/sink adapters) even though its engine already runs on neutral models. Going native removes that plumbing.

Phases 3–5 in the latest commit

A native MSTestTestFramework : ITestFramework, IDataProducer replaces the bridge framework on the flag path and reuses MSTest's existing MSTestDiscoverer/MSTestExecutor engine. New (all #if !WINDOWS_UWP):

  • MSTestFilterContext (MSTestRunContext/MSTestDiscoveryContext) — native IRunContext/IDiscoveryContext that builds the VSTest ITestCaseFilterExpression from the MTP ITestExecutionFilter + --filter + runsettings <TestCaseFilter> (reusing Microsoft.TestPlatform.Filter.Source, now referenced directly). MSTest's existing TestMethodFilter matching is unchanged.
  • MSTestRunSettings — native IRunSettings: reads runsettings, patches MTP defaults (DesignMode/ResultsDirectory/--test-parameter), and warns on unsupported entries (reusing the bridge's already-localized ExtensionResources).
  • MSTestFrameworkHandle — an IFrameworkHandle that only forwards messages to IOutputDevice (results flow through the native recorder).
  • AddMSTest branches the framework factory on the flag; the bridge's shared command-line/config/env-var registrations are kept for now (retired with the dependency in the final step).

Validation

  • Full .\build.cmd — 0 warnings, 0 errors across all TFMs.
  • Unit tests: 45 (MSTestAdapter.UnitTests) + 898 (MSTestAdapter.PlatformServices.UnitTests), all green.
  • Native path (flag on, acceptance):185 tests green — FilterTests, RunsettingsTests (incl. localization), OutputTests, TrxReportTests, ThreadingTests (STA), ServerModeTests, DeploymentItem, DataSourceTests, Inconclusive/Ignore, TestRunParameters, TimeoutTests.
  • Default bridge path (flag off, acceptance):FilterTests + RunsettingsTests (45) — unchanged.

Remaining — Phase 6 (separate, gated)

Flip the default to native and drop the VSTestBridge dependency from MSTest. This is gated on:

  1. Full MSTest acceptance-suite parity on the native path (hundreds of tests — needs CI).
  2. Native replacements for the bridge's remaining shared registrations (the --filter/--settings/--test-parameter option providers and the runsettings config/env-var providers), so the package reference can be removed.

The bridge package itself is not removed — NUnit/Expecto/3rd-party adapters still use it. Only MSTest stops depending on it.

…bridge)
Proposes a staged roadmap to plug MSTest directly into Microsoft.Testing.Platform as a native ITestFramework, replacing the Microsoft.Testing.Extensions.VSTestBridge indirection on the MTP code path. Documents the existing neutral seams (IUnitTestElementSink, ITestResultRecorder, IAdapterMessageLogger, ITestElementFilterProvider, DeploymentContext), a 6-phase plan, capability parity checklist, testing strategy, and risks.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 7, 2026 12:48

CopilotAI 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 adds RFC 018, a design/roadmap document proposing that MSTest plug directly into Microsoft.Testing.Platform (MTP) as a first-class ITestFramework, retiring the Microsoft.Testing.Extensions.VSTestBridge indirection on the MTP code path. It is a documentation-only artifact (status "Under discussion") with no production code changes, intended to let maintainers steer the approach before implementation. The RFC documents the current double-conversion architecture, the existing neutral seams the engine already uses, a 6-phase independently-shippable roadmap, a capability/feature-parity checklist, and the testing strategy, risks, and open questions.

Changes:

  • Documents current vs. target MTP architecture, highlighting the wasteful neutral model → VSTest TestCase/TestResult → TestNode double conversion and the resulting information loss (empty AssemblyFullName/ReturnTypeFullName).
  • Lays out a 6-phase roadmap that keeps the bridge as default until the native path reaches parity, with a feature-parity checklist and dual-run testing strategy.
  • Follows the established docs/RFCs/ convention; the bridge package is not removed (NUnit/Expecto/third-party adapters still use it) — only MSTest stops depending on it.
Show a summary per file
FileDescription
docs/RFCs/018-Native-MTP-Integration-For-MSTest.mdNew RFC describing the native MTP integration design, phasing, parity checklist, testing strategy, risks, and open questions. All referenced types, seams, file paths, and the quoted in-code comment were verified as accurate against the codebase.

Review details

  • Files reviewed: 1/1 changed files
  • Comments generated: 0
  • Review effort level: Medium

@github-actionsgithub-actionsBot 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.

Note

🤖 Automated review by GitHub Copilot. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

#DimensionVerdict
17Documentation Accuracy🟢 2 NIT
21Scope & PR Discipline🟢 1 NIT

✅ 20/22 dimensions N/A (no code changes). 2 dimensions reviewed — only minor nits found.

Summary: This is a well-structured, thoroughly researched RFC. The claims about existing neutral seams (IUnitTestElementSink, ITestResultRecorder, IAdapterMessageLogger, ITestElementFilterProvider) are verified against the codebase, the MSTestBridgedTestFramework information-loss quote is accurate (line 100–106 in that file), and the 6-phase roadmap with the capability parity checklist covers all bridge features I can identify. The design principle of "boundary replacement, not engine rewrite" is well-supported by the architecture diagrams.

  • Path convention: use forward slashes for cross-platform consistency (line 84)
  • Consider linking a tracking issue for the 6-phase roadmap

Comment threaddocs/RFCs/018-Native-MTP-Integration-For-MSTest.md Outdated
Comment threaddocs/RFCs/018-Native-MTP-Integration-For-MSTest.md
Adds the first, unwired building block for plugging MSTest directly into Microsoft.Testing.Platform instead of routing through the VSTest bridge:
- MSTestTestNodeConverter: builds MTP TestNodes directly from MSTest's neutral models (UnitTestElement + framework TestResult), faithfully porting the mapping the bridge does today via ObjectModelConverters/TestResultExtensions/UnitTestElementExtensions (outcome, timing, std out/err, TRX categories/messages/exception/type-name, traits, file location, TestMethodIdentifierProperty).
- MtpUnitTestElementSink / MtpTestResultRecorder: MTP-native IUnitTestElementSink / ITestResultRecorder that publish TestNodeUpdateMessage on the message bus.
- MSTestTestNodeException: native message+stacktrace carrier (replaces the bridge's VSTestException on the MSTest path).
- UnitTestElementExtensions.GetTestId: exposes the stable test id neutrally, without materializing a VSTest TestCase.
The bridge remains the default; these seams are covered by 24 unit tests and are wired in a later phase. No behavior change.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@EvangelinkAmaury Levé (Evangelink) changed the title docs: RFC 018 — native MTP integration for MSTest (retire the VSTest bridge)Native MTP integration for MSTest — RFC 018 + Phase 1 (TestNode production seam)Jul 7, 2026
@github-actions

This comment has been minimized.

When the MSTEST_EXPERIMENTAL_NATIVE_MTP opt-in is set, MSTest publishes discovery and result TestNodes directly via the Phase 1 native converter+seams, bypassing the bridge's ObjectModelConverters / FrameworkHandlerAdapter / TestCaseDiscoverySinkAdapter. The bridge remains the default; only context/filter/config/command-line parsing still flows through it.
Changes:
- VSTestBridge base: expose the session UID as an internal auto-property (bridge already has InternalsVisibleTo MSTest.TestAdapter; no public API change).
- MSTestDiscoverer: add an IUnitTestElementSink overload and share a discovery core so the native sink is used directly instead of discoverySink.ToUnitTestElementSink().
- MSTestExecutor: add a Func<MSTestSettings,ITestResultRecorder> overload and share a run core so a native recorder is used instead of frameworkHandle.ToTestResultRecorder(); the framework handle is still used for message logging and apartment-state handling.
- MSTestBridgedTestFramework: flag-gated native wiring.
Validated: full build 0/0; MSTestAdapter.UnitTests 45/45; native-path acceptance OutputTests(6)+TrxReportTests(3)+Inconclusive/Ignore/DataSource(38) all green; default bridge-path OutputTests(6) unchanged.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 7, 2026 14:04
@EvangelinkAmaury Levé (Evangelink) changed the title Native MTP integration for MSTest — RFC 018 + Phase 1 (TestNode production seam)Native MTP integration for MSTest — RFC 018 + Phase 1 & 2 (opt-in native TestNode path)Jul 7, 2026

CopilotAI 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.

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 5
  • Review effort level: Medium

Comment threadtest/UnitTests/MSTestAdapter.UnitTests/MSTestTestNodeConverterTests.cs Outdated
@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test quality grade — PR #9706

24 new test methods in MSTestTestNodeConverterTests cover MSTestTestNodeConverter, MtpUnitTestElementSink, and MtpTestResultRecorder. All 24 earn A (90–100): clear Arrange-Act-Assert structure, focused single-behavior design, and rich AwesomeAssertions throughout. Two minor opportunities: some tests pass DateTimeOffset.Now as a non-timing parameter (a named constant would be cleaner), and one negative test omits an absence assertion for symmetry with its enabled counterpart.

GradeTestNotes
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordEmptyResult_
PublishesNothing
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordResult_
PublishesResultNodeAndReturnsFailedFlag
Tests both return value and published state; consider splitting into two focused tests for sharper isolation.
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordResult_
ReturnsFalse_
ForPassedTest
Return value correctly checked; consider also asserting the published node carries PassedTestNodeStateProperty for symmetry.
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordStart_
PublishesInProgressNode
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
MtpUnitTestElementSink_
PublishesDiscoveredTestNode
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsCategoriesAndTraitsAsMetadata
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsFileLocation_
WhenDeclaringFileKnown
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsTestMethodIdentifier_
FromManagedNames
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsTrxCategories_
OnlyWhenTrxEnabled
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
DoesNotAddFileLocation_
WhenDeclaringFileUnknown
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
DoesNotAddTestMethodIdentifier_
WhenNoManagedMethodName
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
SetsUidDisplayNameAndDiscoveredState
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
UsesExplicitDisplayName_
WhenProvided
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToInProgressTestNode_
AddsInProgressState
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
AddsTimingProperty
Uses explicit deterministic timestamps; duration equality verified — no issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
AddsTrxProperties_
WhenTrxEnabled
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
DoesNotAddTrxProperties_
WhenTrxDisabled
Consider also asserting TrxFullyQualifiedTypeNameProperty absence for symmetry with the enabled test.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
IncludesDebugTraceAndTestContextBannersInStandardOutput
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsFailedOutcome_
WithMessageAndStackTrace
Both exception fields verified; replace DateTimeOffset.Now in non-timing args with a fixed constant for clarity.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsIgnoredOutcomeToSkipped
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsInconclusiveToSkipped_
ByDefault
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsLogOutputAndLogErrorToStandardStreams
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsNotFoundOutcomeToError
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsPassedOutcome
No issues found.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Generated by the Grade Tests on PR (on open / sync) workflow. · 145.8 AIC · ⌖ 10.8 AIC · ⊞ 9.5K · [◷]( · )

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jul 7, 2026
- Make the neutral discovery/result seams asynchronous end-to-end (per review): ITestResultRecorder (RecordStartAsync/RecordEmptyResultAsync/RecordResultAsync) and IUnitTestElementSink (SendTestElementAsync). Thread async through UnitTestDiscoverer (DiscoverTestsAsync/DiscoverTestsInSourceAsync/SendTestCasesAsync) and TestExecutionManager.SendTestResultsAsync. The MTP implementations now await the message-bus publish instead of blocking with GetAwaiter().GetResult(); the VSTest implementations return completed tasks (sync fast-path preserves STA behavior).
- Add the UTF-8 BOM required by .editorconfig to the five new .cs files.
- Use forward slashes for the seam path in RFC 018.
Validated: full build 0/0; unit tests MSTestAdapter.UnitTests 45/45 and MSTestAdapter.PlatformServices.UnitTests 898/898; acceptance default-path threading/output/trx 41 green; native-path threading/output/trx/outcome/data-driven 75 green.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@Evangelink
Amaury Levé (Evangelink) enabled auto-merge (squash) July 8, 2026 10:16
@Evangelink
Amaury Levé (Evangelink) merged commit 641c192 into mainJul 8, 2026
101 of 102 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/remove-vstest-bridge-mstest branch July 8, 2026 12:02
github-actionsBot added a commit that referenced this pull request Jul 8, 2026
Apply two project-convention improvements to files added in recent PRs:
- MSTestTestNodeConverter.cs (added in #9706): replace Substring calls
with range operators per csharp_style_prefer_range_operator = true
- TestMethodRunner.DataSource.cs (added in #9729): replace == null with
is null per the project's 'always use is null / is not null' rule
No behavioral change; builds verified to succeed with 0 errors.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@EvangelinkAmaury Levé (Evangelink) changed the title Native MTP integration for MSTest — RFC 018 + Phase 1 & 2 (opt-in native TestNode path)Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path)Jul 8, 2026
github-actionsBot added a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Amaury Levé (Evangelink) pushed a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-reviewAwaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Evangelink@0101
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path) - #9706

Merged
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest
Jul 8, 2026
Merged

Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path)#9706
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest

Conversation

@Evangelink

@EvangelinkAmaury Levé (Evangelink) commented Jul 7, 2026

Copy link
Copy Markdown
Member

What

Works toward removing the Microsoft.Testing.Extensions.VSTestBridge dependency from MSTest's Microsoft.Testing.Platform (MTP) code path, so MSTest plugs into MTP natively. Delivered as a reviewable, phased series — all behind the opt-in MSTEST_EXPERIMENTAL_NATIVE_MTP switch, so the shipping default (the bridge) is unchanged.

  • RFC 018 — the roadmap/design (docs/RFCs/018-...md).
  • Phase 1 — native TestNode production seam (MSTestTestNodeConverter, MtpUnitTestElementSink, MtpTestResultRecorder).
  • Phase 2 — proved the seams by wiring them behind the flag (now superseded by the native framework).
  • Phases 3–5 — a native MSTestTestFramework that handles the MTP request directly: native filtering, runsettings/config, message logging, and session lifecycle. No VSTest bridge object-model adapters on the native request path.
  • Review feedback addressed (async neutral seams, UTF-8 BOM, doc style).

Why

On the MTP path, MSTest round-trips through the VSTest object model (context/filter/runsettings/handle/sink adapters) even though its engine already runs on neutral models. Going native removes that plumbing.

Phases 3–5 in the latest commit

A native MSTestTestFramework : ITestFramework, IDataProducer replaces the bridge framework on the flag path and reuses MSTest's existing MSTestDiscoverer/MSTestExecutor engine. New (all #if !WINDOWS_UWP):

  • MSTestFilterContext (MSTestRunContext/MSTestDiscoveryContext) — native IRunContext/IDiscoveryContext that builds the VSTest ITestCaseFilterExpression from the MTP ITestExecutionFilter + --filter + runsettings <TestCaseFilter> (reusing Microsoft.TestPlatform.Filter.Source, now referenced directly). MSTest's existing TestMethodFilter matching is unchanged.
  • MSTestRunSettings — native IRunSettings: reads runsettings, patches MTP defaults (DesignMode/ResultsDirectory/--test-parameter), and warns on unsupported entries (reusing the bridge's already-localized ExtensionResources).
  • MSTestFrameworkHandle — an IFrameworkHandle that only forwards messages to IOutputDevice (results flow through the native recorder).
  • AddMSTest branches the framework factory on the flag; the bridge's shared command-line/config/env-var registrations are kept for now (retired with the dependency in the final step).

Validation

  • Full .\build.cmd — 0 warnings, 0 errors across all TFMs.
  • Unit tests: 45 (MSTestAdapter.UnitTests) + 898 (MSTestAdapter.PlatformServices.UnitTests), all green.
  • Native path (flag on, acceptance):185 tests green — FilterTests, RunsettingsTests (incl. localization), OutputTests, TrxReportTests, ThreadingTests (STA), ServerModeTests, DeploymentItem, DataSourceTests, Inconclusive/Ignore, TestRunParameters, TimeoutTests.
  • Default bridge path (flag off, acceptance):FilterTests + RunsettingsTests (45) — unchanged.

Remaining — Phase 6 (separate, gated)

Flip the default to native and drop the VSTestBridge dependency from MSTest. This is gated on:

  1. Full MSTest acceptance-suite parity on the native path (hundreds of tests — needs CI).
  2. Native replacements for the bridge's remaining shared registrations (the --filter/--settings/--test-parameter option providers and the runsettings config/env-var providers), so the package reference can be removed.

The bridge package itself is not removed — NUnit/Expecto/3rd-party adapters still use it. Only MSTest stops depending on it.

…bridge)
Proposes a staged roadmap to plug MSTest directly into Microsoft.Testing.Platform as a native ITestFramework, replacing the Microsoft.Testing.Extensions.VSTestBridge indirection on the MTP code path. Documents the existing neutral seams (IUnitTestElementSink, ITestResultRecorder, IAdapterMessageLogger, ITestElementFilterProvider, DeploymentContext), a 6-phase plan, capability parity checklist, testing strategy, and risks.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 7, 2026 12:48

CopilotAI 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 adds RFC 018, a design/roadmap document proposing that MSTest plug directly into Microsoft.Testing.Platform (MTP) as a first-class ITestFramework, retiring the Microsoft.Testing.Extensions.VSTestBridge indirection on the MTP code path. It is a documentation-only artifact (status "Under discussion") with no production code changes, intended to let maintainers steer the approach before implementation. The RFC documents the current double-conversion architecture, the existing neutral seams the engine already uses, a 6-phase independently-shippable roadmap, a capability/feature-parity checklist, and the testing strategy, risks, and open questions.

Changes:

  • Documents current vs. target MTP architecture, highlighting the wasteful neutral model → VSTest TestCase/TestResult → TestNode double conversion and the resulting information loss (empty AssemblyFullName/ReturnTypeFullName).
  • Lays out a 6-phase roadmap that keeps the bridge as default until the native path reaches parity, with a feature-parity checklist and dual-run testing strategy.
  • Follows the established docs/RFCs/ convention; the bridge package is not removed (NUnit/Expecto/third-party adapters still use it) — only MSTest stops depending on it.
Show a summary per file
FileDescription
docs/RFCs/018-Native-MTP-Integration-For-MSTest.mdNew RFC describing the native MTP integration design, phasing, parity checklist, testing strategy, risks, and open questions. All referenced types, seams, file paths, and the quoted in-code comment were verified as accurate against the codebase.

Review details

  • Files reviewed: 1/1 changed files
  • Comments generated: 0
  • Review effort level: Medium

@github-actionsgithub-actionsBot 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.

Note

🤖 Automated review by GitHub Copilot. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

#DimensionVerdict
17Documentation Accuracy🟢 2 NIT
21Scope & PR Discipline🟢 1 NIT

✅ 20/22 dimensions N/A (no code changes). 2 dimensions reviewed — only minor nits found.

Summary: This is a well-structured, thoroughly researched RFC. The claims about existing neutral seams (IUnitTestElementSink, ITestResultRecorder, IAdapterMessageLogger, ITestElementFilterProvider) are verified against the codebase, the MSTestBridgedTestFramework information-loss quote is accurate (line 100–106 in that file), and the 6-phase roadmap with the capability parity checklist covers all bridge features I can identify. The design principle of "boundary replacement, not engine rewrite" is well-supported by the architecture diagrams.

  • Path convention: use forward slashes for cross-platform consistency (line 84)
  • Consider linking a tracking issue for the 6-phase roadmap

Comment threaddocs/RFCs/018-Native-MTP-Integration-For-MSTest.md Outdated
Comment threaddocs/RFCs/018-Native-MTP-Integration-For-MSTest.md
Adds the first, unwired building block for plugging MSTest directly into Microsoft.Testing.Platform instead of routing through the VSTest bridge:
- MSTestTestNodeConverter: builds MTP TestNodes directly from MSTest's neutral models (UnitTestElement + framework TestResult), faithfully porting the mapping the bridge does today via ObjectModelConverters/TestResultExtensions/UnitTestElementExtensions (outcome, timing, std out/err, TRX categories/messages/exception/type-name, traits, file location, TestMethodIdentifierProperty).
- MtpUnitTestElementSink / MtpTestResultRecorder: MTP-native IUnitTestElementSink / ITestResultRecorder that publish TestNodeUpdateMessage on the message bus.
- MSTestTestNodeException: native message+stacktrace carrier (replaces the bridge's VSTestException on the MSTest path).
- UnitTestElementExtensions.GetTestId: exposes the stable test id neutrally, without materializing a VSTest TestCase.
The bridge remains the default; these seams are covered by 24 unit tests and are wired in a later phase. No behavior change.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@EvangelinkAmaury Levé (Evangelink) changed the title docs: RFC 018 — native MTP integration for MSTest (retire the VSTest bridge)Native MTP integration for MSTest — RFC 018 + Phase 1 (TestNode production seam)Jul 7, 2026
@github-actions

This comment has been minimized.

When the MSTEST_EXPERIMENTAL_NATIVE_MTP opt-in is set, MSTest publishes discovery and result TestNodes directly via the Phase 1 native converter+seams, bypassing the bridge's ObjectModelConverters / FrameworkHandlerAdapter / TestCaseDiscoverySinkAdapter. The bridge remains the default; only context/filter/config/command-line parsing still flows through it.
Changes:
- VSTestBridge base: expose the session UID as an internal auto-property (bridge already has InternalsVisibleTo MSTest.TestAdapter; no public API change).
- MSTestDiscoverer: add an IUnitTestElementSink overload and share a discovery core so the native sink is used directly instead of discoverySink.ToUnitTestElementSink().
- MSTestExecutor: add a Func<MSTestSettings,ITestResultRecorder> overload and share a run core so a native recorder is used instead of frameworkHandle.ToTestResultRecorder(); the framework handle is still used for message logging and apartment-state handling.
- MSTestBridgedTestFramework: flag-gated native wiring.
Validated: full build 0/0; MSTestAdapter.UnitTests 45/45; native-path acceptance OutputTests(6)+TrxReportTests(3)+Inconclusive/Ignore/DataSource(38) all green; default bridge-path OutputTests(6) unchanged.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 7, 2026 14:04
@EvangelinkAmaury Levé (Evangelink) changed the title Native MTP integration for MSTest — RFC 018 + Phase 1 (TestNode production seam)Native MTP integration for MSTest — RFC 018 + Phase 1 & 2 (opt-in native TestNode path)Jul 7, 2026

CopilotAI 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.

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 5
  • Review effort level: Medium

Comment threadtest/UnitTests/MSTestAdapter.UnitTests/MSTestTestNodeConverterTests.cs Outdated
@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test quality grade — PR #9706

24 new test methods in MSTestTestNodeConverterTests cover MSTestTestNodeConverter, MtpUnitTestElementSink, and MtpTestResultRecorder. All 24 earn A (90–100): clear Arrange-Act-Assert structure, focused single-behavior design, and rich AwesomeAssertions throughout. Two minor opportunities: some tests pass DateTimeOffset.Now as a non-timing parameter (a named constant would be cleaner), and one negative test omits an absence assertion for symmetry with its enabled counterpart.

GradeTestNotes
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordEmptyResult_
PublishesNothing
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordResult_
PublishesResultNodeAndReturnsFailedFlag
Tests both return value and published state; consider splitting into two focused tests for sharper isolation.
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordResult_
ReturnsFalse_
ForPassedTest
Return value correctly checked; consider also asserting the published node carries PassedTestNodeStateProperty for symmetry.
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordStart_
PublishesInProgressNode
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
MtpUnitTestElementSink_
PublishesDiscoveredTestNode
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsCategoriesAndTraitsAsMetadata
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsFileLocation_
WhenDeclaringFileKnown
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsTestMethodIdentifier_
FromManagedNames
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsTrxCategories_
OnlyWhenTrxEnabled
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
DoesNotAddFileLocation_
WhenDeclaringFileUnknown
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
DoesNotAddTestMethodIdentifier_
WhenNoManagedMethodName
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
SetsUidDisplayNameAndDiscoveredState
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
UsesExplicitDisplayName_
WhenProvided
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToInProgressTestNode_
AddsInProgressState
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
AddsTimingProperty
Uses explicit deterministic timestamps; duration equality verified — no issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
AddsTrxProperties_
WhenTrxEnabled
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
DoesNotAddTrxProperties_
WhenTrxDisabled
Consider also asserting TrxFullyQualifiedTypeNameProperty absence for symmetry with the enabled test.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
IncludesDebugTraceAndTestContextBannersInStandardOutput
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsFailedOutcome_
WithMessageAndStackTrace
Both exception fields verified; replace DateTimeOffset.Now in non-timing args with a fixed constant for clarity.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsIgnoredOutcomeToSkipped
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsInconclusiveToSkipped_
ByDefault
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsLogOutputAndLogErrorToStandardStreams
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsNotFoundOutcomeToError
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsPassedOutcome
No issues found.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Generated by the Grade Tests on PR (on open / sync) workflow. · 145.8 AIC · ⌖ 10.8 AIC · ⊞ 9.5K · [◷]( · )

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jul 7, 2026
- Make the neutral discovery/result seams asynchronous end-to-end (per review): ITestResultRecorder (RecordStartAsync/RecordEmptyResultAsync/RecordResultAsync) and IUnitTestElementSink (SendTestElementAsync). Thread async through UnitTestDiscoverer (DiscoverTestsAsync/DiscoverTestsInSourceAsync/SendTestCasesAsync) and TestExecutionManager.SendTestResultsAsync. The MTP implementations now await the message-bus publish instead of blocking with GetAwaiter().GetResult(); the VSTest implementations return completed tasks (sync fast-path preserves STA behavior).
- Add the UTF-8 BOM required by .editorconfig to the five new .cs files.
- Use forward slashes for the seam path in RFC 018.
Validated: full build 0/0; unit tests MSTestAdapter.UnitTests 45/45 and MSTestAdapter.PlatformServices.UnitTests 898/898; acceptance default-path threading/output/trx 41 green; native-path threading/output/trx/outcome/data-driven 75 green.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@Evangelink
Amaury Levé (Evangelink) enabled auto-merge (squash) July 8, 2026 10:16
@Evangelink
Amaury Levé (Evangelink) merged commit 641c192 into mainJul 8, 2026
101 of 102 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/remove-vstest-bridge-mstest branch July 8, 2026 12:02
github-actionsBot added a commit that referenced this pull request Jul 8, 2026
Apply two project-convention improvements to files added in recent PRs:
- MSTestTestNodeConverter.cs (added in #9706): replace Substring calls
with range operators per csharp_style_prefer_range_operator = true
- TestMethodRunner.DataSource.cs (added in #9729): replace == null with
is null per the project's 'always use is null / is not null' rule
No behavioral change; builds verified to succeed with 0 errors.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@EvangelinkAmaury Levé (Evangelink) changed the title Native MTP integration for MSTest — RFC 018 + Phase 1 & 2 (opt-in native TestNode path)Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path)Jul 8, 2026
github-actionsBot added a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Amaury Levé (Evangelink) pushed a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-reviewAwaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Evangelink@0101
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path) - #9706

Merged
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest
Jul 8, 2026
Merged

Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path)#9706
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest

Conversation

@Evangelink

@EvangelinkAmaury Levé (Evangelink) commented Jul 7, 2026

Copy link
Copy Markdown
Member

What

Works toward removing the Microsoft.Testing.Extensions.VSTestBridge dependency from MSTest's Microsoft.Testing.Platform (MTP) code path, so MSTest plugs into MTP natively. Delivered as a reviewable, phased series — all behind the opt-in MSTEST_EXPERIMENTAL_NATIVE_MTP switch, so the shipping default (the bridge) is unchanged.

  • RFC 018 — the roadmap/design (docs/RFCs/018-...md).
  • Phase 1 — native TestNode production seam (MSTestTestNodeConverter, MtpUnitTestElementSink, MtpTestResultRecorder).
  • Phase 2 — proved the seams by wiring them behind the flag (now superseded by the native framework).
  • Phases 3–5 — a native MSTestTestFramework that handles the MTP request directly: native filtering, runsettings/config, message logging, and session lifecycle. No VSTest bridge object-model adapters on the native request path.
  • Review feedback addressed (async neutral seams, UTF-8 BOM, doc style).

Why

On the MTP path, MSTest round-trips through the VSTest object model (context/filter/runsettings/handle/sink adapters) even though its engine already runs on neutral models. Going native removes that plumbing.

Phases 3–5 in the latest commit

A native MSTestTestFramework : ITestFramework, IDataProducer replaces the bridge framework on the flag path and reuses MSTest's existing MSTestDiscoverer/MSTestExecutor engine. New (all #if !WINDOWS_UWP):

  • MSTestFilterContext (MSTestRunContext/MSTestDiscoveryContext) — native IRunContext/IDiscoveryContext that builds the VSTest ITestCaseFilterExpression from the MTP ITestExecutionFilter + --filter + runsettings <TestCaseFilter> (reusing Microsoft.TestPlatform.Filter.Source, now referenced directly). MSTest's existing TestMethodFilter matching is unchanged.
  • MSTestRunSettings — native IRunSettings: reads runsettings, patches MTP defaults (DesignMode/ResultsDirectory/--test-parameter), and warns on unsupported entries (reusing the bridge's already-localized ExtensionResources).
  • MSTestFrameworkHandle — an IFrameworkHandle that only forwards messages to IOutputDevice (results flow through the native recorder).
  • AddMSTest branches the framework factory on the flag; the bridge's shared command-line/config/env-var registrations are kept for now (retired with the dependency in the final step).

Validation

  • Full .\build.cmd — 0 warnings, 0 errors across all TFMs.
  • Unit tests: 45 (MSTestAdapter.UnitTests) + 898 (MSTestAdapter.PlatformServices.UnitTests), all green.
  • Native path (flag on, acceptance):185 tests green — FilterTests, RunsettingsTests (incl. localization), OutputTests, TrxReportTests, ThreadingTests (STA), ServerModeTests, DeploymentItem, DataSourceTests, Inconclusive/Ignore, TestRunParameters, TimeoutTests.
  • Default bridge path (flag off, acceptance):FilterTests + RunsettingsTests (45) — unchanged.

Remaining — Phase 6 (separate, gated)

Flip the default to native and drop the VSTestBridge dependency from MSTest. This is gated on:

  1. Full MSTest acceptance-suite parity on the native path (hundreds of tests — needs CI).
  2. Native replacements for the bridge's remaining shared registrations (the --filter/--settings/--test-parameter option providers and the runsettings config/env-var providers), so the package reference can be removed.

The bridge package itself is not removed — NUnit/Expecto/3rd-party adapters still use it. Only MSTest stops depending on it.

…bridge)
Proposes a staged roadmap to plug MSTest directly into Microsoft.Testing.Platform as a native ITestFramework, replacing the Microsoft.Testing.Extensions.VSTestBridge indirection on the MTP code path. Documents the existing neutral seams (IUnitTestElementSink, ITestResultRecorder, IAdapterMessageLogger, ITestElementFilterProvider, DeploymentContext), a 6-phase plan, capability parity checklist, testing strategy, and risks.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 7, 2026 12:48

CopilotAI 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 adds RFC 018, a design/roadmap document proposing that MSTest plug directly into Microsoft.Testing.Platform (MTP) as a first-class ITestFramework, retiring the Microsoft.Testing.Extensions.VSTestBridge indirection on the MTP code path. It is a documentation-only artifact (status "Under discussion") with no production code changes, intended to let maintainers steer the approach before implementation. The RFC documents the current double-conversion architecture, the existing neutral seams the engine already uses, a 6-phase independently-shippable roadmap, a capability/feature-parity checklist, and the testing strategy, risks, and open questions.

Changes:

  • Documents current vs. target MTP architecture, highlighting the wasteful neutral model → VSTest TestCase/TestResult → TestNode double conversion and the resulting information loss (empty AssemblyFullName/ReturnTypeFullName).
  • Lays out a 6-phase roadmap that keeps the bridge as default until the native path reaches parity, with a feature-parity checklist and dual-run testing strategy.
  • Follows the established docs/RFCs/ convention; the bridge package is not removed (NUnit/Expecto/third-party adapters still use it) — only MSTest stops depending on it.
Show a summary per file
FileDescription
docs/RFCs/018-Native-MTP-Integration-For-MSTest.mdNew RFC describing the native MTP integration design, phasing, parity checklist, testing strategy, risks, and open questions. All referenced types, seams, file paths, and the quoted in-code comment were verified as accurate against the codebase.

Review details

  • Files reviewed: 1/1 changed files
  • Comments generated: 0
  • Review effort level: Medium

@github-actionsgithub-actionsBot 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.

Note

🤖 Automated review by GitHub Copilot. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

#DimensionVerdict
17Documentation Accuracy🟢 2 NIT
21Scope & PR Discipline🟢 1 NIT

✅ 20/22 dimensions N/A (no code changes). 2 dimensions reviewed — only minor nits found.

Summary: This is a well-structured, thoroughly researched RFC. The claims about existing neutral seams (IUnitTestElementSink, ITestResultRecorder, IAdapterMessageLogger, ITestElementFilterProvider) are verified against the codebase, the MSTestBridgedTestFramework information-loss quote is accurate (line 100–106 in that file), and the 6-phase roadmap with the capability parity checklist covers all bridge features I can identify. The design principle of "boundary replacement, not engine rewrite" is well-supported by the architecture diagrams.

  • Path convention: use forward slashes for cross-platform consistency (line 84)
  • Consider linking a tracking issue for the 6-phase roadmap

Comment threaddocs/RFCs/018-Native-MTP-Integration-For-MSTest.md Outdated
Comment threaddocs/RFCs/018-Native-MTP-Integration-For-MSTest.md
Adds the first, unwired building block for plugging MSTest directly into Microsoft.Testing.Platform instead of routing through the VSTest bridge:
- MSTestTestNodeConverter: builds MTP TestNodes directly from MSTest's neutral models (UnitTestElement + framework TestResult), faithfully porting the mapping the bridge does today via ObjectModelConverters/TestResultExtensions/UnitTestElementExtensions (outcome, timing, std out/err, TRX categories/messages/exception/type-name, traits, file location, TestMethodIdentifierProperty).
- MtpUnitTestElementSink / MtpTestResultRecorder: MTP-native IUnitTestElementSink / ITestResultRecorder that publish TestNodeUpdateMessage on the message bus.
- MSTestTestNodeException: native message+stacktrace carrier (replaces the bridge's VSTestException on the MSTest path).
- UnitTestElementExtensions.GetTestId: exposes the stable test id neutrally, without materializing a VSTest TestCase.
The bridge remains the default; these seams are covered by 24 unit tests and are wired in a later phase. No behavior change.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@EvangelinkAmaury Levé (Evangelink) changed the title docs: RFC 018 — native MTP integration for MSTest (retire the VSTest bridge)Native MTP integration for MSTest — RFC 018 + Phase 1 (TestNode production seam)Jul 7, 2026
@github-actions

This comment has been minimized.

When the MSTEST_EXPERIMENTAL_NATIVE_MTP opt-in is set, MSTest publishes discovery and result TestNodes directly via the Phase 1 native converter+seams, bypassing the bridge's ObjectModelConverters / FrameworkHandlerAdapter / TestCaseDiscoverySinkAdapter. The bridge remains the default; only context/filter/config/command-line parsing still flows through it.
Changes:
- VSTestBridge base: expose the session UID as an internal auto-property (bridge already has InternalsVisibleTo MSTest.TestAdapter; no public API change).
- MSTestDiscoverer: add an IUnitTestElementSink overload and share a discovery core so the native sink is used directly instead of discoverySink.ToUnitTestElementSink().
- MSTestExecutor: add a Func<MSTestSettings,ITestResultRecorder> overload and share a run core so a native recorder is used instead of frameworkHandle.ToTestResultRecorder(); the framework handle is still used for message logging and apartment-state handling.
- MSTestBridgedTestFramework: flag-gated native wiring.
Validated: full build 0/0; MSTestAdapter.UnitTests 45/45; native-path acceptance OutputTests(6)+TrxReportTests(3)+Inconclusive/Ignore/DataSource(38) all green; default bridge-path OutputTests(6) unchanged.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 7, 2026 14:04
@EvangelinkAmaury Levé (Evangelink) changed the title Native MTP integration for MSTest — RFC 018 + Phase 1 (TestNode production seam)Native MTP integration for MSTest — RFC 018 + Phase 1 & 2 (opt-in native TestNode path)Jul 7, 2026

CopilotAI 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.

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 5
  • Review effort level: Medium

Comment threadtest/UnitTests/MSTestAdapter.UnitTests/MSTestTestNodeConverterTests.cs Outdated
@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test quality grade — PR #9706

24 new test methods in MSTestTestNodeConverterTests cover MSTestTestNodeConverter, MtpUnitTestElementSink, and MtpTestResultRecorder. All 24 earn A (90–100): clear Arrange-Act-Assert structure, focused single-behavior design, and rich AwesomeAssertions throughout. Two minor opportunities: some tests pass DateTimeOffset.Now as a non-timing parameter (a named constant would be cleaner), and one negative test omits an absence assertion for symmetry with its enabled counterpart.

GradeTestNotes
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordEmptyResult_
PublishesNothing
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordResult_
PublishesResultNodeAndReturnsFailedFlag
Tests both return value and published state; consider splitting into two focused tests for sharper isolation.
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordResult_
ReturnsFalse_
ForPassedTest
Return value correctly checked; consider also asserting the published node carries PassedTestNodeStateProperty for symmetry.
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordStart_
PublishesInProgressNode
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
MtpUnitTestElementSink_
PublishesDiscoveredTestNode
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsCategoriesAndTraitsAsMetadata
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsFileLocation_
WhenDeclaringFileKnown
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsTestMethodIdentifier_
FromManagedNames
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsTrxCategories_
OnlyWhenTrxEnabled
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
DoesNotAddFileLocation_
WhenDeclaringFileUnknown
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
DoesNotAddTestMethodIdentifier_
WhenNoManagedMethodName
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
SetsUidDisplayNameAndDiscoveredState
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
UsesExplicitDisplayName_
WhenProvided
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToInProgressTestNode_
AddsInProgressState
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
AddsTimingProperty
Uses explicit deterministic timestamps; duration equality verified — no issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
AddsTrxProperties_
WhenTrxEnabled
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
DoesNotAddTrxProperties_
WhenTrxDisabled
Consider also asserting TrxFullyQualifiedTypeNameProperty absence for symmetry with the enabled test.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
IncludesDebugTraceAndTestContextBannersInStandardOutput
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsFailedOutcome_
WithMessageAndStackTrace
Both exception fields verified; replace DateTimeOffset.Now in non-timing args with a fixed constant for clarity.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsIgnoredOutcomeToSkipped
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsInconclusiveToSkipped_
ByDefault
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsLogOutputAndLogErrorToStandardStreams
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsNotFoundOutcomeToError
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsPassedOutcome
No issues found.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Generated by the Grade Tests on PR (on open / sync) workflow. · 145.8 AIC · ⌖ 10.8 AIC · ⊞ 9.5K · [◷]( · )

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jul 7, 2026
- Make the neutral discovery/result seams asynchronous end-to-end (per review): ITestResultRecorder (RecordStartAsync/RecordEmptyResultAsync/RecordResultAsync) and IUnitTestElementSink (SendTestElementAsync). Thread async through UnitTestDiscoverer (DiscoverTestsAsync/DiscoverTestsInSourceAsync/SendTestCasesAsync) and TestExecutionManager.SendTestResultsAsync. The MTP implementations now await the message-bus publish instead of blocking with GetAwaiter().GetResult(); the VSTest implementations return completed tasks (sync fast-path preserves STA behavior).
- Add the UTF-8 BOM required by .editorconfig to the five new .cs files.
- Use forward slashes for the seam path in RFC 018.
Validated: full build 0/0; unit tests MSTestAdapter.UnitTests 45/45 and MSTestAdapter.PlatformServices.UnitTests 898/898; acceptance default-path threading/output/trx 41 green; native-path threading/output/trx/outcome/data-driven 75 green.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@Evangelink
Amaury Levé (Evangelink) enabled auto-merge (squash) July 8, 2026 10:16
@Evangelink
Amaury Levé (Evangelink) merged commit 641c192 into mainJul 8, 2026
101 of 102 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/remove-vstest-bridge-mstest branch July 8, 2026 12:02
github-actionsBot added a commit that referenced this pull request Jul 8, 2026
Apply two project-convention improvements to files added in recent PRs:
- MSTestTestNodeConverter.cs (added in #9706): replace Substring calls
with range operators per csharp_style_prefer_range_operator = true
- TestMethodRunner.DataSource.cs (added in #9729): replace == null with
is null per the project's 'always use is null / is not null' rule
No behavioral change; builds verified to succeed with 0 errors.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@EvangelinkAmaury Levé (Evangelink) changed the title Native MTP integration for MSTest — RFC 018 + Phase 1 & 2 (opt-in native TestNode path)Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path)Jul 8, 2026
github-actionsBot added a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Amaury Levé (Evangelink) pushed a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-reviewAwaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Evangelink@0101
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path) - #9706

Merged
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest
Jul 8, 2026
Merged

Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path)#9706
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest

Conversation

@Evangelink

@EvangelinkAmaury Levé (Evangelink) commented Jul 7, 2026

Copy link
Copy Markdown
Member

What

Works toward removing the Microsoft.Testing.Extensions.VSTestBridge dependency from MSTest's Microsoft.Testing.Platform (MTP) code path, so MSTest plugs into MTP natively. Delivered as a reviewable, phased series — all behind the opt-in MSTEST_EXPERIMENTAL_NATIVE_MTP switch, so the shipping default (the bridge) is unchanged.

  • RFC 018 — the roadmap/design (docs/RFCs/018-...md).
  • Phase 1 — native TestNode production seam (MSTestTestNodeConverter, MtpUnitTestElementSink, MtpTestResultRecorder).
  • Phase 2 — proved the seams by wiring them behind the flag (now superseded by the native framework).
  • Phases 3–5 — a native MSTestTestFramework that handles the MTP request directly: native filtering, runsettings/config, message logging, and session lifecycle. No VSTest bridge object-model adapters on the native request path.
  • Review feedback addressed (async neutral seams, UTF-8 BOM, doc style).

Why

On the MTP path, MSTest round-trips through the VSTest object model (context/filter/runsettings/handle/sink adapters) even though its engine already runs on neutral models. Going native removes that plumbing.

Phases 3–5 in the latest commit

A native MSTestTestFramework : ITestFramework, IDataProducer replaces the bridge framework on the flag path and reuses MSTest's existing MSTestDiscoverer/MSTestExecutor engine. New (all #if !WINDOWS_UWP):

  • MSTestFilterContext (MSTestRunContext/MSTestDiscoveryContext) — native IRunContext/IDiscoveryContext that builds the VSTest ITestCaseFilterExpression from the MTP ITestExecutionFilter + --filter + runsettings <TestCaseFilter> (reusing Microsoft.TestPlatform.Filter.Source, now referenced directly). MSTest's existing TestMethodFilter matching is unchanged.
  • MSTestRunSettings — native IRunSettings: reads runsettings, patches MTP defaults (DesignMode/ResultsDirectory/--test-parameter), and warns on unsupported entries (reusing the bridge's already-localized ExtensionResources).
  • MSTestFrameworkHandle — an IFrameworkHandle that only forwards messages to IOutputDevice (results flow through the native recorder).
  • AddMSTest branches the framework factory on the flag; the bridge's shared command-line/config/env-var registrations are kept for now (retired with the dependency in the final step).

Validation

  • Full .\build.cmd — 0 warnings, 0 errors across all TFMs.
  • Unit tests: 45 (MSTestAdapter.UnitTests) + 898 (MSTestAdapter.PlatformServices.UnitTests), all green.
  • Native path (flag on, acceptance):185 tests green — FilterTests, RunsettingsTests (incl. localization), OutputTests, TrxReportTests, ThreadingTests (STA), ServerModeTests, DeploymentItem, DataSourceTests, Inconclusive/Ignore, TestRunParameters, TimeoutTests.
  • Default bridge path (flag off, acceptance):FilterTests + RunsettingsTests (45) — unchanged.

Remaining — Phase 6 (separate, gated)

Flip the default to native and drop the VSTestBridge dependency from MSTest. This is gated on:

  1. Full MSTest acceptance-suite parity on the native path (hundreds of tests — needs CI).
  2. Native replacements for the bridge's remaining shared registrations (the --filter/--settings/--test-parameter option providers and the runsettings config/env-var providers), so the package reference can be removed.

The bridge package itself is not removed — NUnit/Expecto/3rd-party adapters still use it. Only MSTest stops depending on it.

…bridge)
Proposes a staged roadmap to plug MSTest directly into Microsoft.Testing.Platform as a native ITestFramework, replacing the Microsoft.Testing.Extensions.VSTestBridge indirection on the MTP code path. Documents the existing neutral seams (IUnitTestElementSink, ITestResultRecorder, IAdapterMessageLogger, ITestElementFilterProvider, DeploymentContext), a 6-phase plan, capability parity checklist, testing strategy, and risks.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 7, 2026 12:48

CopilotAI 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 adds RFC 018, a design/roadmap document proposing that MSTest plug directly into Microsoft.Testing.Platform (MTP) as a first-class ITestFramework, retiring the Microsoft.Testing.Extensions.VSTestBridge indirection on the MTP code path. It is a documentation-only artifact (status "Under discussion") with no production code changes, intended to let maintainers steer the approach before implementation. The RFC documents the current double-conversion architecture, the existing neutral seams the engine already uses, a 6-phase independently-shippable roadmap, a capability/feature-parity checklist, and the testing strategy, risks, and open questions.

Changes:

  • Documents current vs. target MTP architecture, highlighting the wasteful neutral model → VSTest TestCase/TestResult → TestNode double conversion and the resulting information loss (empty AssemblyFullName/ReturnTypeFullName).
  • Lays out a 6-phase roadmap that keeps the bridge as default until the native path reaches parity, with a feature-parity checklist and dual-run testing strategy.
  • Follows the established docs/RFCs/ convention; the bridge package is not removed (NUnit/Expecto/third-party adapters still use it) — only MSTest stops depending on it.
Show a summary per file
FileDescription
docs/RFCs/018-Native-MTP-Integration-For-MSTest.mdNew RFC describing the native MTP integration design, phasing, parity checklist, testing strategy, risks, and open questions. All referenced types, seams, file paths, and the quoted in-code comment were verified as accurate against the codebase.

Review details

  • Files reviewed: 1/1 changed files
  • Comments generated: 0
  • Review effort level: Medium

@github-actionsgithub-actionsBot 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.

Note

🤖 Automated review by GitHub Copilot. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

#DimensionVerdict
17Documentation Accuracy🟢 2 NIT
21Scope & PR Discipline🟢 1 NIT

✅ 20/22 dimensions N/A (no code changes). 2 dimensions reviewed — only minor nits found.

Summary: This is a well-structured, thoroughly researched RFC. The claims about existing neutral seams (IUnitTestElementSink, ITestResultRecorder, IAdapterMessageLogger, ITestElementFilterProvider) are verified against the codebase, the MSTestBridgedTestFramework information-loss quote is accurate (line 100–106 in that file), and the 6-phase roadmap with the capability parity checklist covers all bridge features I can identify. The design principle of "boundary replacement, not engine rewrite" is well-supported by the architecture diagrams.

  • Path convention: use forward slashes for cross-platform consistency (line 84)
  • Consider linking a tracking issue for the 6-phase roadmap

Comment threaddocs/RFCs/018-Native-MTP-Integration-For-MSTest.md Outdated
Comment threaddocs/RFCs/018-Native-MTP-Integration-For-MSTest.md
Adds the first, unwired building block for plugging MSTest directly into Microsoft.Testing.Platform instead of routing through the VSTest bridge:
- MSTestTestNodeConverter: builds MTP TestNodes directly from MSTest's neutral models (UnitTestElement + framework TestResult), faithfully porting the mapping the bridge does today via ObjectModelConverters/TestResultExtensions/UnitTestElementExtensions (outcome, timing, std out/err, TRX categories/messages/exception/type-name, traits, file location, TestMethodIdentifierProperty).
- MtpUnitTestElementSink / MtpTestResultRecorder: MTP-native IUnitTestElementSink / ITestResultRecorder that publish TestNodeUpdateMessage on the message bus.
- MSTestTestNodeException: native message+stacktrace carrier (replaces the bridge's VSTestException on the MSTest path).
- UnitTestElementExtensions.GetTestId: exposes the stable test id neutrally, without materializing a VSTest TestCase.
The bridge remains the default; these seams are covered by 24 unit tests and are wired in a later phase. No behavior change.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@EvangelinkAmaury Levé (Evangelink) changed the title docs: RFC 018 — native MTP integration for MSTest (retire the VSTest bridge)Native MTP integration for MSTest — RFC 018 + Phase 1 (TestNode production seam)Jul 7, 2026
@github-actions

This comment has been minimized.

When the MSTEST_EXPERIMENTAL_NATIVE_MTP opt-in is set, MSTest publishes discovery and result TestNodes directly via the Phase 1 native converter+seams, bypassing the bridge's ObjectModelConverters / FrameworkHandlerAdapter / TestCaseDiscoverySinkAdapter. The bridge remains the default; only context/filter/config/command-line parsing still flows through it.
Changes:
- VSTestBridge base: expose the session UID as an internal auto-property (bridge already has InternalsVisibleTo MSTest.TestAdapter; no public API change).
- MSTestDiscoverer: add an IUnitTestElementSink overload and share a discovery core so the native sink is used directly instead of discoverySink.ToUnitTestElementSink().
- MSTestExecutor: add a Func<MSTestSettings,ITestResultRecorder> overload and share a run core so a native recorder is used instead of frameworkHandle.ToTestResultRecorder(); the framework handle is still used for message logging and apartment-state handling.
- MSTestBridgedTestFramework: flag-gated native wiring.
Validated: full build 0/0; MSTestAdapter.UnitTests 45/45; native-path acceptance OutputTests(6)+TrxReportTests(3)+Inconclusive/Ignore/DataSource(38) all green; default bridge-path OutputTests(6) unchanged.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 7, 2026 14:04
@EvangelinkAmaury Levé (Evangelink) changed the title Native MTP integration for MSTest — RFC 018 + Phase 1 (TestNode production seam)Native MTP integration for MSTest — RFC 018 + Phase 1 & 2 (opt-in native TestNode path)Jul 7, 2026

CopilotAI 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.

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 5
  • Review effort level: Medium

Comment threadtest/UnitTests/MSTestAdapter.UnitTests/MSTestTestNodeConverterTests.cs Outdated
@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test quality grade — PR #9706

24 new test methods in MSTestTestNodeConverterTests cover MSTestTestNodeConverter, MtpUnitTestElementSink, and MtpTestResultRecorder. All 24 earn A (90–100): clear Arrange-Act-Assert structure, focused single-behavior design, and rich AwesomeAssertions throughout. Two minor opportunities: some tests pass DateTimeOffset.Now as a non-timing parameter (a named constant would be cleaner), and one negative test omits an absence assertion for symmetry with its enabled counterpart.

GradeTestNotes
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordEmptyResult_
PublishesNothing
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordResult_
PublishesResultNodeAndReturnsFailedFlag
Tests both return value and published state; consider splitting into two focused tests for sharper isolation.
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordResult_
ReturnsFalse_
ForPassedTest
Return value correctly checked; consider also asserting the published node carries PassedTestNodeStateProperty for symmetry.
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordStart_
PublishesInProgressNode
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
MtpUnitTestElementSink_
PublishesDiscoveredTestNode
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsCategoriesAndTraitsAsMetadata
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsFileLocation_
WhenDeclaringFileKnown
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsTestMethodIdentifier_
FromManagedNames
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsTrxCategories_
OnlyWhenTrxEnabled
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
DoesNotAddFileLocation_
WhenDeclaringFileUnknown
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
DoesNotAddTestMethodIdentifier_
WhenNoManagedMethodName
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
SetsUidDisplayNameAndDiscoveredState
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
UsesExplicitDisplayName_
WhenProvided
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToInProgressTestNode_
AddsInProgressState
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
AddsTimingProperty
Uses explicit deterministic timestamps; duration equality verified — no issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
AddsTrxProperties_
WhenTrxEnabled
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
DoesNotAddTrxProperties_
WhenTrxDisabled
Consider also asserting TrxFullyQualifiedTypeNameProperty absence for symmetry with the enabled test.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
IncludesDebugTraceAndTestContextBannersInStandardOutput
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsFailedOutcome_
WithMessageAndStackTrace
Both exception fields verified; replace DateTimeOffset.Now in non-timing args with a fixed constant for clarity.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsIgnoredOutcomeToSkipped
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsInconclusiveToSkipped_
ByDefault
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsLogOutputAndLogErrorToStandardStreams
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsNotFoundOutcomeToError
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsPassedOutcome
No issues found.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Generated by the Grade Tests on PR (on open / sync) workflow. · 145.8 AIC · ⌖ 10.8 AIC · ⊞ 9.5K · [◷]( · )

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jul 7, 2026
- Make the neutral discovery/result seams asynchronous end-to-end (per review): ITestResultRecorder (RecordStartAsync/RecordEmptyResultAsync/RecordResultAsync) and IUnitTestElementSink (SendTestElementAsync). Thread async through UnitTestDiscoverer (DiscoverTestsAsync/DiscoverTestsInSourceAsync/SendTestCasesAsync) and TestExecutionManager.SendTestResultsAsync. The MTP implementations now await the message-bus publish instead of blocking with GetAwaiter().GetResult(); the VSTest implementations return completed tasks (sync fast-path preserves STA behavior).
- Add the UTF-8 BOM required by .editorconfig to the five new .cs files.
- Use forward slashes for the seam path in RFC 018.
Validated: full build 0/0; unit tests MSTestAdapter.UnitTests 45/45 and MSTestAdapter.PlatformServices.UnitTests 898/898; acceptance default-path threading/output/trx 41 green; native-path threading/output/trx/outcome/data-driven 75 green.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@Evangelink
Amaury Levé (Evangelink) enabled auto-merge (squash) July 8, 2026 10:16
@Evangelink
Amaury Levé (Evangelink) merged commit 641c192 into mainJul 8, 2026
101 of 102 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/remove-vstest-bridge-mstest branch July 8, 2026 12:02
github-actionsBot added a commit that referenced this pull request Jul 8, 2026
Apply two project-convention improvements to files added in recent PRs:
- MSTestTestNodeConverter.cs (added in #9706): replace Substring calls
with range operators per csharp_style_prefer_range_operator = true
- TestMethodRunner.DataSource.cs (added in #9729): replace == null with
is null per the project's 'always use is null / is not null' rule
No behavioral change; builds verified to succeed with 0 errors.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@EvangelinkAmaury Levé (Evangelink) changed the title Native MTP integration for MSTest — RFC 018 + Phase 1 & 2 (opt-in native TestNode path)Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path)Jul 8, 2026
github-actionsBot added a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Amaury Levé (Evangelink) pushed a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-reviewAwaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Evangelink@0101
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path) - #9706

Merged
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest
Jul 8, 2026
Merged

Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path)#9706
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest

Conversation

@Evangelink

@EvangelinkAmaury Levé (Evangelink) commented Jul 7, 2026

Copy link
Copy Markdown
Member

What

Works toward removing the Microsoft.Testing.Extensions.VSTestBridge dependency from MSTest's Microsoft.Testing.Platform (MTP) code path, so MSTest plugs into MTP natively. Delivered as a reviewable, phased series — all behind the opt-in MSTEST_EXPERIMENTAL_NATIVE_MTP switch, so the shipping default (the bridge) is unchanged.

  • RFC 018 — the roadmap/design (docs/RFCs/018-...md).
  • Phase 1 — native TestNode production seam (MSTestTestNodeConverter, MtpUnitTestElementSink, MtpTestResultRecorder).
  • Phase 2 — proved the seams by wiring them behind the flag (now superseded by the native framework).
  • Phases 3–5 — a native MSTestTestFramework that handles the MTP request directly: native filtering, runsettings/config, message logging, and session lifecycle. No VSTest bridge object-model adapters on the native request path.
  • Review feedback addressed (async neutral seams, UTF-8 BOM, doc style).

Why

On the MTP path, MSTest round-trips through the VSTest object model (context/filter/runsettings/handle/sink adapters) even though its engine already runs on neutral models. Going native removes that plumbing.

Phases 3–5 in the latest commit

A native MSTestTestFramework : ITestFramework, IDataProducer replaces the bridge framework on the flag path and reuses MSTest's existing MSTestDiscoverer/MSTestExecutor engine. New (all #if !WINDOWS_UWP):

  • MSTestFilterContext (MSTestRunContext/MSTestDiscoveryContext) — native IRunContext/IDiscoveryContext that builds the VSTest ITestCaseFilterExpression from the MTP ITestExecutionFilter + --filter + runsettings <TestCaseFilter> (reusing Microsoft.TestPlatform.Filter.Source, now referenced directly). MSTest's existing TestMethodFilter matching is unchanged.
  • MSTestRunSettings — native IRunSettings: reads runsettings, patches MTP defaults (DesignMode/ResultsDirectory/--test-parameter), and warns on unsupported entries (reusing the bridge's already-localized ExtensionResources).
  • MSTestFrameworkHandle — an IFrameworkHandle that only forwards messages to IOutputDevice (results flow through the native recorder).
  • AddMSTest branches the framework factory on the flag; the bridge's shared command-line/config/env-var registrations are kept for now (retired with the dependency in the final step).

Validation

  • Full .\build.cmd — 0 warnings, 0 errors across all TFMs.
  • Unit tests: 45 (MSTestAdapter.UnitTests) + 898 (MSTestAdapter.PlatformServices.UnitTests), all green.
  • Native path (flag on, acceptance):185 tests green — FilterTests, RunsettingsTests (incl. localization), OutputTests, TrxReportTests, ThreadingTests (STA), ServerModeTests, DeploymentItem, DataSourceTests, Inconclusive/Ignore, TestRunParameters, TimeoutTests.
  • Default bridge path (flag off, acceptance):FilterTests + RunsettingsTests (45) — unchanged.

Remaining — Phase 6 (separate, gated)

Flip the default to native and drop the VSTestBridge dependency from MSTest. This is gated on:

  1. Full MSTest acceptance-suite parity on the native path (hundreds of tests — needs CI).
  2. Native replacements for the bridge's remaining shared registrations (the --filter/--settings/--test-parameter option providers and the runsettings config/env-var providers), so the package reference can be removed.

The bridge package itself is not removed — NUnit/Expecto/3rd-party adapters still use it. Only MSTest stops depending on it.

…bridge)
Proposes a staged roadmap to plug MSTest directly into Microsoft.Testing.Platform as a native ITestFramework, replacing the Microsoft.Testing.Extensions.VSTestBridge indirection on the MTP code path. Documents the existing neutral seams (IUnitTestElementSink, ITestResultRecorder, IAdapterMessageLogger, ITestElementFilterProvider, DeploymentContext), a 6-phase plan, capability parity checklist, testing strategy, and risks.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 7, 2026 12:48

CopilotAI 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 adds RFC 018, a design/roadmap document proposing that MSTest plug directly into Microsoft.Testing.Platform (MTP) as a first-class ITestFramework, retiring the Microsoft.Testing.Extensions.VSTestBridge indirection on the MTP code path. It is a documentation-only artifact (status "Under discussion") with no production code changes, intended to let maintainers steer the approach before implementation. The RFC documents the current double-conversion architecture, the existing neutral seams the engine already uses, a 6-phase independently-shippable roadmap, a capability/feature-parity checklist, and the testing strategy, risks, and open questions.

Changes:

  • Documents current vs. target MTP architecture, highlighting the wasteful neutral model → VSTest TestCase/TestResult → TestNode double conversion and the resulting information loss (empty AssemblyFullName/ReturnTypeFullName).
  • Lays out a 6-phase roadmap that keeps the bridge as default until the native path reaches parity, with a feature-parity checklist and dual-run testing strategy.
  • Follows the established docs/RFCs/ convention; the bridge package is not removed (NUnit/Expecto/third-party adapters still use it) — only MSTest stops depending on it.
Show a summary per file
FileDescription
docs/RFCs/018-Native-MTP-Integration-For-MSTest.mdNew RFC describing the native MTP integration design, phasing, parity checklist, testing strategy, risks, and open questions. All referenced types, seams, file paths, and the quoted in-code comment were verified as accurate against the codebase.

Review details

  • Files reviewed: 1/1 changed files
  • Comments generated: 0
  • Review effort level: Medium

@github-actionsgithub-actionsBot 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.

Note

🤖 Automated review by GitHub Copilot. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

#DimensionVerdict
17Documentation Accuracy🟢 2 NIT
21Scope & PR Discipline🟢 1 NIT

✅ 20/22 dimensions N/A (no code changes). 2 dimensions reviewed — only minor nits found.

Summary: This is a well-structured, thoroughly researched RFC. The claims about existing neutral seams (IUnitTestElementSink, ITestResultRecorder, IAdapterMessageLogger, ITestElementFilterProvider) are verified against the codebase, the MSTestBridgedTestFramework information-loss quote is accurate (line 100–106 in that file), and the 6-phase roadmap with the capability parity checklist covers all bridge features I can identify. The design principle of "boundary replacement, not engine rewrite" is well-supported by the architecture diagrams.

  • Path convention: use forward slashes for cross-platform consistency (line 84)
  • Consider linking a tracking issue for the 6-phase roadmap

Comment threaddocs/RFCs/018-Native-MTP-Integration-For-MSTest.md Outdated
Comment threaddocs/RFCs/018-Native-MTP-Integration-For-MSTest.md
Adds the first, unwired building block for plugging MSTest directly into Microsoft.Testing.Platform instead of routing through the VSTest bridge:
- MSTestTestNodeConverter: builds MTP TestNodes directly from MSTest's neutral models (UnitTestElement + framework TestResult), faithfully porting the mapping the bridge does today via ObjectModelConverters/TestResultExtensions/UnitTestElementExtensions (outcome, timing, std out/err, TRX categories/messages/exception/type-name, traits, file location, TestMethodIdentifierProperty).
- MtpUnitTestElementSink / MtpTestResultRecorder: MTP-native IUnitTestElementSink / ITestResultRecorder that publish TestNodeUpdateMessage on the message bus.
- MSTestTestNodeException: native message+stacktrace carrier (replaces the bridge's VSTestException on the MSTest path).
- UnitTestElementExtensions.GetTestId: exposes the stable test id neutrally, without materializing a VSTest TestCase.
The bridge remains the default; these seams are covered by 24 unit tests and are wired in a later phase. No behavior change.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@EvangelinkAmaury Levé (Evangelink) changed the title docs: RFC 018 — native MTP integration for MSTest (retire the VSTest bridge)Native MTP integration for MSTest — RFC 018 + Phase 1 (TestNode production seam)Jul 7, 2026
@github-actions

This comment has been minimized.

When the MSTEST_EXPERIMENTAL_NATIVE_MTP opt-in is set, MSTest publishes discovery and result TestNodes directly via the Phase 1 native converter+seams, bypassing the bridge's ObjectModelConverters / FrameworkHandlerAdapter / TestCaseDiscoverySinkAdapter. The bridge remains the default; only context/filter/config/command-line parsing still flows through it.
Changes:
- VSTestBridge base: expose the session UID as an internal auto-property (bridge already has InternalsVisibleTo MSTest.TestAdapter; no public API change).
- MSTestDiscoverer: add an IUnitTestElementSink overload and share a discovery core so the native sink is used directly instead of discoverySink.ToUnitTestElementSink().
- MSTestExecutor: add a Func<MSTestSettings,ITestResultRecorder> overload and share a run core so a native recorder is used instead of frameworkHandle.ToTestResultRecorder(); the framework handle is still used for message logging and apartment-state handling.
- MSTestBridgedTestFramework: flag-gated native wiring.
Validated: full build 0/0; MSTestAdapter.UnitTests 45/45; native-path acceptance OutputTests(6)+TrxReportTests(3)+Inconclusive/Ignore/DataSource(38) all green; default bridge-path OutputTests(6) unchanged.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 7, 2026 14:04
@EvangelinkAmaury Levé (Evangelink) changed the title Native MTP integration for MSTest — RFC 018 + Phase 1 (TestNode production seam)Native MTP integration for MSTest — RFC 018 + Phase 1 & 2 (opt-in native TestNode path)Jul 7, 2026

CopilotAI 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.

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 5
  • Review effort level: Medium

Comment threadtest/UnitTests/MSTestAdapter.UnitTests/MSTestTestNodeConverterTests.cs Outdated
@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test quality grade — PR #9706

24 new test methods in MSTestTestNodeConverterTests cover MSTestTestNodeConverter, MtpUnitTestElementSink, and MtpTestResultRecorder. All 24 earn A (90–100): clear Arrange-Act-Assert structure, focused single-behavior design, and rich AwesomeAssertions throughout. Two minor opportunities: some tests pass DateTimeOffset.Now as a non-timing parameter (a named constant would be cleaner), and one negative test omits an absence assertion for symmetry with its enabled counterpart.

GradeTestNotes
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordEmptyResult_
PublishesNothing
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordResult_
PublishesResultNodeAndReturnsFailedFlag
Tests both return value and published state; consider splitting into two focused tests for sharper isolation.
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordResult_
ReturnsFalse_
ForPassedTest
Return value correctly checked; consider also asserting the published node carries PassedTestNodeStateProperty for symmetry.
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordStart_
PublishesInProgressNode
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
MtpUnitTestElementSink_
PublishesDiscoveredTestNode
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsCategoriesAndTraitsAsMetadata
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsFileLocation_
WhenDeclaringFileKnown
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsTestMethodIdentifier_
FromManagedNames
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsTrxCategories_
OnlyWhenTrxEnabled
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
DoesNotAddFileLocation_
WhenDeclaringFileUnknown
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
DoesNotAddTestMethodIdentifier_
WhenNoManagedMethodName
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
SetsUidDisplayNameAndDiscoveredState
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
UsesExplicitDisplayName_
WhenProvided
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToInProgressTestNode_
AddsInProgressState
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
AddsTimingProperty
Uses explicit deterministic timestamps; duration equality verified — no issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
AddsTrxProperties_
WhenTrxEnabled
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
DoesNotAddTrxProperties_
WhenTrxDisabled
Consider also asserting TrxFullyQualifiedTypeNameProperty absence for symmetry with the enabled test.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
IncludesDebugTraceAndTestContextBannersInStandardOutput
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsFailedOutcome_
WithMessageAndStackTrace
Both exception fields verified; replace DateTimeOffset.Now in non-timing args with a fixed constant for clarity.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsIgnoredOutcomeToSkipped
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsInconclusiveToSkipped_
ByDefault
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsLogOutputAndLogErrorToStandardStreams
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsNotFoundOutcomeToError
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsPassedOutcome
No issues found.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Generated by the Grade Tests on PR (on open / sync) workflow. · 145.8 AIC · ⌖ 10.8 AIC · ⊞ 9.5K · [◷]( · )

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jul 7, 2026
- Make the neutral discovery/result seams asynchronous end-to-end (per review): ITestResultRecorder (RecordStartAsync/RecordEmptyResultAsync/RecordResultAsync) and IUnitTestElementSink (SendTestElementAsync). Thread async through UnitTestDiscoverer (DiscoverTestsAsync/DiscoverTestsInSourceAsync/SendTestCasesAsync) and TestExecutionManager.SendTestResultsAsync. The MTP implementations now await the message-bus publish instead of blocking with GetAwaiter().GetResult(); the VSTest implementations return completed tasks (sync fast-path preserves STA behavior).
- Add the UTF-8 BOM required by .editorconfig to the five new .cs files.
- Use forward slashes for the seam path in RFC 018.
Validated: full build 0/0; unit tests MSTestAdapter.UnitTests 45/45 and MSTestAdapter.PlatformServices.UnitTests 898/898; acceptance default-path threading/output/trx 41 green; native-path threading/output/trx/outcome/data-driven 75 green.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@Evangelink
Amaury Levé (Evangelink) enabled auto-merge (squash) July 8, 2026 10:16
@Evangelink
Amaury Levé (Evangelink) merged commit 641c192 into mainJul 8, 2026
101 of 102 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/remove-vstest-bridge-mstest branch July 8, 2026 12:02
github-actionsBot added a commit that referenced this pull request Jul 8, 2026
Apply two project-convention improvements to files added in recent PRs:
- MSTestTestNodeConverter.cs (added in #9706): replace Substring calls
with range operators per csharp_style_prefer_range_operator = true
- TestMethodRunner.DataSource.cs (added in #9729): replace == null with
is null per the project's 'always use is null / is not null' rule
No behavioral change; builds verified to succeed with 0 errors.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@EvangelinkAmaury Levé (Evangelink) changed the title Native MTP integration for MSTest — RFC 018 + Phase 1 & 2 (opt-in native TestNode path)Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path)Jul 8, 2026
github-actionsBot added a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Amaury Levé (Evangelink) pushed a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-reviewAwaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Evangelink@0101
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path) - #9706

Merged
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest
Jul 8, 2026
Merged

Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path)#9706
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest

Conversation

@Evangelink

@EvangelinkAmaury Levé (Evangelink) commented Jul 7, 2026

Copy link
Copy Markdown
Member

What

Works toward removing the Microsoft.Testing.Extensions.VSTestBridge dependency from MSTest's Microsoft.Testing.Platform (MTP) code path, so MSTest plugs into MTP natively. Delivered as a reviewable, phased series — all behind the opt-in MSTEST_EXPERIMENTAL_NATIVE_MTP switch, so the shipping default (the bridge) is unchanged.

  • RFC 018 — the roadmap/design (docs/RFCs/018-...md).
  • Phase 1 — native TestNode production seam (MSTestTestNodeConverter, MtpUnitTestElementSink, MtpTestResultRecorder).
  • Phase 2 — proved the seams by wiring them behind the flag (now superseded by the native framework).
  • Phases 3–5 — a native MSTestTestFramework that handles the MTP request directly: native filtering, runsettings/config, message logging, and session lifecycle. No VSTest bridge object-model adapters on the native request path.
  • Review feedback addressed (async neutral seams, UTF-8 BOM, doc style).

Why

On the MTP path, MSTest round-trips through the VSTest object model (context/filter/runsettings/handle/sink adapters) even though its engine already runs on neutral models. Going native removes that plumbing.

Phases 3–5 in the latest commit

A native MSTestTestFramework : ITestFramework, IDataProducer replaces the bridge framework on the flag path and reuses MSTest's existing MSTestDiscoverer/MSTestExecutor engine. New (all #if !WINDOWS_UWP):

  • MSTestFilterContext (MSTestRunContext/MSTestDiscoveryContext) — native IRunContext/IDiscoveryContext that builds the VSTest ITestCaseFilterExpression from the MTP ITestExecutionFilter + --filter + runsettings <TestCaseFilter> (reusing Microsoft.TestPlatform.Filter.Source, now referenced directly). MSTest's existing TestMethodFilter matching is unchanged.
  • MSTestRunSettings — native IRunSettings: reads runsettings, patches MTP defaults (DesignMode/ResultsDirectory/--test-parameter), and warns on unsupported entries (reusing the bridge's already-localized ExtensionResources).
  • MSTestFrameworkHandle — an IFrameworkHandle that only forwards messages to IOutputDevice (results flow through the native recorder).
  • AddMSTest branches the framework factory on the flag; the bridge's shared command-line/config/env-var registrations are kept for now (retired with the dependency in the final step).

Validation

  • Full .\build.cmd — 0 warnings, 0 errors across all TFMs.
  • Unit tests: 45 (MSTestAdapter.UnitTests) + 898 (MSTestAdapter.PlatformServices.UnitTests), all green.
  • Native path (flag on, acceptance):185 tests green — FilterTests, RunsettingsTests (incl. localization), OutputTests, TrxReportTests, ThreadingTests (STA), ServerModeTests, DeploymentItem, DataSourceTests, Inconclusive/Ignore, TestRunParameters, TimeoutTests.
  • Default bridge path (flag off, acceptance):FilterTests + RunsettingsTests (45) — unchanged.

Remaining — Phase 6 (separate, gated)

Flip the default to native and drop the VSTestBridge dependency from MSTest. This is gated on:

  1. Full MSTest acceptance-suite parity on the native path (hundreds of tests — needs CI).
  2. Native replacements for the bridge's remaining shared registrations (the --filter/--settings/--test-parameter option providers and the runsettings config/env-var providers), so the package reference can be removed.

The bridge package itself is not removed — NUnit/Expecto/3rd-party adapters still use it. Only MSTest stops depending on it.

…bridge)
Proposes a staged roadmap to plug MSTest directly into Microsoft.Testing.Platform as a native ITestFramework, replacing the Microsoft.Testing.Extensions.VSTestBridge indirection on the MTP code path. Documents the existing neutral seams (IUnitTestElementSink, ITestResultRecorder, IAdapterMessageLogger, ITestElementFilterProvider, DeploymentContext), a 6-phase plan, capability parity checklist, testing strategy, and risks.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 7, 2026 12:48

CopilotAI 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 adds RFC 018, a design/roadmap document proposing that MSTest plug directly into Microsoft.Testing.Platform (MTP) as a first-class ITestFramework, retiring the Microsoft.Testing.Extensions.VSTestBridge indirection on the MTP code path. It is a documentation-only artifact (status "Under discussion") with no production code changes, intended to let maintainers steer the approach before implementation. The RFC documents the current double-conversion architecture, the existing neutral seams the engine already uses, a 6-phase independently-shippable roadmap, a capability/feature-parity checklist, and the testing strategy, risks, and open questions.

Changes:

  • Documents current vs. target MTP architecture, highlighting the wasteful neutral model → VSTest TestCase/TestResult → TestNode double conversion and the resulting information loss (empty AssemblyFullName/ReturnTypeFullName).
  • Lays out a 6-phase roadmap that keeps the bridge as default until the native path reaches parity, with a feature-parity checklist and dual-run testing strategy.
  • Follows the established docs/RFCs/ convention; the bridge package is not removed (NUnit/Expecto/third-party adapters still use it) — only MSTest stops depending on it.
Show a summary per file
FileDescription
docs/RFCs/018-Native-MTP-Integration-For-MSTest.mdNew RFC describing the native MTP integration design, phasing, parity checklist, testing strategy, risks, and open questions. All referenced types, seams, file paths, and the quoted in-code comment were verified as accurate against the codebase.

Review details

  • Files reviewed: 1/1 changed files
  • Comments generated: 0
  • Review effort level: Medium

@github-actionsgithub-actionsBot 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.

Note

🤖 Automated review by GitHub Copilot. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

#DimensionVerdict
17Documentation Accuracy🟢 2 NIT
21Scope & PR Discipline🟢 1 NIT

✅ 20/22 dimensions N/A (no code changes). 2 dimensions reviewed — only minor nits found.

Summary: This is a well-structured, thoroughly researched RFC. The claims about existing neutral seams (IUnitTestElementSink, ITestResultRecorder, IAdapterMessageLogger, ITestElementFilterProvider) are verified against the codebase, the MSTestBridgedTestFramework information-loss quote is accurate (line 100–106 in that file), and the 6-phase roadmap with the capability parity checklist covers all bridge features I can identify. The design principle of "boundary replacement, not engine rewrite" is well-supported by the architecture diagrams.

  • Path convention: use forward slashes for cross-platform consistency (line 84)
  • Consider linking a tracking issue for the 6-phase roadmap

Comment threaddocs/RFCs/018-Native-MTP-Integration-For-MSTest.md Outdated
Comment threaddocs/RFCs/018-Native-MTP-Integration-For-MSTest.md
Adds the first, unwired building block for plugging MSTest directly into Microsoft.Testing.Platform instead of routing through the VSTest bridge:
- MSTestTestNodeConverter: builds MTP TestNodes directly from MSTest's neutral models (UnitTestElement + framework TestResult), faithfully porting the mapping the bridge does today via ObjectModelConverters/TestResultExtensions/UnitTestElementExtensions (outcome, timing, std out/err, TRX categories/messages/exception/type-name, traits, file location, TestMethodIdentifierProperty).
- MtpUnitTestElementSink / MtpTestResultRecorder: MTP-native IUnitTestElementSink / ITestResultRecorder that publish TestNodeUpdateMessage on the message bus.
- MSTestTestNodeException: native message+stacktrace carrier (replaces the bridge's VSTestException on the MSTest path).
- UnitTestElementExtensions.GetTestId: exposes the stable test id neutrally, without materializing a VSTest TestCase.
The bridge remains the default; these seams are covered by 24 unit tests and are wired in a later phase. No behavior change.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@EvangelinkAmaury Levé (Evangelink) changed the title docs: RFC 018 — native MTP integration for MSTest (retire the VSTest bridge)Native MTP integration for MSTest — RFC 018 + Phase 1 (TestNode production seam)Jul 7, 2026
@github-actions

This comment has been minimized.

When the MSTEST_EXPERIMENTAL_NATIVE_MTP opt-in is set, MSTest publishes discovery and result TestNodes directly via the Phase 1 native converter+seams, bypassing the bridge's ObjectModelConverters / FrameworkHandlerAdapter / TestCaseDiscoverySinkAdapter. The bridge remains the default; only context/filter/config/command-line parsing still flows through it.
Changes:
- VSTestBridge base: expose the session UID as an internal auto-property (bridge already has InternalsVisibleTo MSTest.TestAdapter; no public API change).
- MSTestDiscoverer: add an IUnitTestElementSink overload and share a discovery core so the native sink is used directly instead of discoverySink.ToUnitTestElementSink().
- MSTestExecutor: add a Func<MSTestSettings,ITestResultRecorder> overload and share a run core so a native recorder is used instead of frameworkHandle.ToTestResultRecorder(); the framework handle is still used for message logging and apartment-state handling.
- MSTestBridgedTestFramework: flag-gated native wiring.
Validated: full build 0/0; MSTestAdapter.UnitTests 45/45; native-path acceptance OutputTests(6)+TrxReportTests(3)+Inconclusive/Ignore/DataSource(38) all green; default bridge-path OutputTests(6) unchanged.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 7, 2026 14:04
@EvangelinkAmaury Levé (Evangelink) changed the title Native MTP integration for MSTest — RFC 018 + Phase 1 (TestNode production seam)Native MTP integration for MSTest — RFC 018 + Phase 1 & 2 (opt-in native TestNode path)Jul 7, 2026

CopilotAI 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.

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 5
  • Review effort level: Medium

Comment threadtest/UnitTests/MSTestAdapter.UnitTests/MSTestTestNodeConverterTests.cs Outdated
@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test quality grade — PR #9706

24 new test methods in MSTestTestNodeConverterTests cover MSTestTestNodeConverter, MtpUnitTestElementSink, and MtpTestResultRecorder. All 24 earn A (90–100): clear Arrange-Act-Assert structure, focused single-behavior design, and rich AwesomeAssertions throughout. Two minor opportunities: some tests pass DateTimeOffset.Now as a non-timing parameter (a named constant would be cleaner), and one negative test omits an absence assertion for symmetry with its enabled counterpart.

GradeTestNotes
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordEmptyResult_
PublishesNothing
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordResult_
PublishesResultNodeAndReturnsFailedFlag
Tests both return value and published state; consider splitting into two focused tests for sharper isolation.
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordResult_
ReturnsFalse_
ForPassedTest
Return value correctly checked; consider also asserting the published node carries PassedTestNodeStateProperty for symmetry.
A (90–100)new MSTestTestNodeConverterTests.
MtpTestResultRecorder_
RecordStart_
PublishesInProgressNode
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
MtpUnitTestElementSink_
PublishesDiscoveredTestNode
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsCategoriesAndTraitsAsMetadata
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsFileLocation_
WhenDeclaringFileKnown
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsTestMethodIdentifier_
FromManagedNames
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
AddsTrxCategories_
OnlyWhenTrxEnabled
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
DoesNotAddFileLocation_
WhenDeclaringFileUnknown
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
DoesNotAddTestMethodIdentifier_
WhenNoManagedMethodName
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
SetsUidDisplayNameAndDiscoveredState
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToDiscoveredTestNode_
UsesExplicitDisplayName_
WhenProvided
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToInProgressTestNode_
AddsInProgressState
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
AddsTimingProperty
Uses explicit deterministic timestamps; duration equality verified — no issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
AddsTrxProperties_
WhenTrxEnabled
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
DoesNotAddTrxProperties_
WhenTrxDisabled
Consider also asserting TrxFullyQualifiedTypeNameProperty absence for symmetry with the enabled test.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
IncludesDebugTraceAndTestContextBannersInStandardOutput
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsFailedOutcome_
WithMessageAndStackTrace
Both exception fields verified; replace DateTimeOffset.Now in non-timing args with a fixed constant for clarity.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsIgnoredOutcomeToSkipped
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsInconclusiveToSkipped_
ByDefault
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsLogOutputAndLogErrorToStandardStreams
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsNotFoundOutcomeToError
No issues found.
A (90–100)new MSTestTestNodeConverterTests.
ToResultTestNode_
MapsPassedOutcome
No issues found.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Generated by the Grade Tests on PR (on open / sync) workflow. · 145.8 AIC · ⌖ 10.8 AIC · ⊞ 9.5K · [◷]( · )

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jul 7, 2026
- Make the neutral discovery/result seams asynchronous end-to-end (per review): ITestResultRecorder (RecordStartAsync/RecordEmptyResultAsync/RecordResultAsync) and IUnitTestElementSink (SendTestElementAsync). Thread async through UnitTestDiscoverer (DiscoverTestsAsync/DiscoverTestsInSourceAsync/SendTestCasesAsync) and TestExecutionManager.SendTestResultsAsync. The MTP implementations now await the message-bus publish instead of blocking with GetAwaiter().GetResult(); the VSTest implementations return completed tasks (sync fast-path preserves STA behavior).
- Add the UTF-8 BOM required by .editorconfig to the five new .cs files.
- Use forward slashes for the seam path in RFC 018.
Validated: full build 0/0; unit tests MSTestAdapter.UnitTests 45/45 and MSTestAdapter.PlatformServices.UnitTests 898/898; acceptance default-path threading/output/trx 41 green; native-path threading/output/trx/outcome/data-driven 75 green.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@Evangelink
Amaury Levé (Evangelink) enabled auto-merge (squash) July 8, 2026 10:16
@Evangelink
Amaury Levé (Evangelink) merged commit 641c192 into mainJul 8, 2026
101 of 102 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/remove-vstest-bridge-mstest branch July 8, 2026 12:02
github-actionsBot added a commit that referenced this pull request Jul 8, 2026
Apply two project-convention improvements to files added in recent PRs:
- MSTestTestNodeConverter.cs (added in #9706): replace Substring calls
with range operators per csharp_style_prefer_range_operator = true
- TestMethodRunner.DataSource.cs (added in #9729): replace == null with
is null per the project's 'always use is null / is not null' rule
No behavioral change; builds verified to succeed with 0 errors.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@EvangelinkAmaury Levé (Evangelink) changed the title Native MTP integration for MSTest — RFC 018 + Phase 1 & 2 (opt-in native TestNode path)Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path)Jul 8, 2026
github-actionsBot added a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Amaury Levé (Evangelink) pushed a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-reviewAwaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Evangelink@0101