Skip to content

Abstract VSTest result reporting in PlatformServices (Phase 5 of platform-agnostic effort)#9550

Merged
Evangelink merged 2 commits into
mainfrom
dev/amauryleve/abstract-vstest-results-platformservices
Jul 3, 2026
Merged

Abstract VSTest result reporting in PlatformServices (Phase 5 of platform-agnostic effort)#9550
Evangelink merged 2 commits into
mainfrom
dev/amauryleve/abstract-vstest-results-platformservices

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Why

Part of the multi-PR effort to make MSTestAdapter.PlatformServices platform-agnostic by removing its dependency on the VSTest object model (Microsoft.VisualStudio.TestPlatform.ObjectModel.*). The VSTest coupling is being concentrated into small adapter-facing bridges so it can later be lifted entirely out of PlatformServices.

Phase 5 targets the execution result / output path: the VSTest result-side types (TestResult, TestOutcome, TestResultMessage, AttachmentSet, UriDataAttachment) and the recorder role used to report results.

What

  • New neutral abstraction ITestResultRecorder (Interfaces/ITestResultRecorder.cs, namespace …PlatformServices.Interface): a functional, platform-agnostic sink with RecordStart / RecordEmptyResult / RecordResult(TestCase, framework TestResult, start, end). It carries no VSTest result-type naming and reuses the framework TestResult.
  • Single VSTest translation point HostTestResultRecorder behind TestResultRecorderExtensions.ToTestResultRecorder(this ITestExecutionRecorder, computerName, settings) (Services/TestResultRecorderExtensions.cs, namespace …PlatformServices). This bridge is the only place that builds a VSTest TestResult/TestOutcome, records attachments/messages, and calls the VSTest recorder — mirroring the Phase 1 IAdapterMessageLogger + AdapterMessageLoggerExtensions pattern.
  • Execution/TestExecutionManager.Runner.cs now reports start/empty/result through ITestResultRecorder, so it no longer constructs any VSTest result-side type. The VSTest recorder is wrapped once at the boundary (inside ExecuteTestsWithTestRunnerAsync) to avoid touching Phase 1 files.
  • TestResultExtensions.ToTestResult and UnitTestOutcomeHelper.ToTestOutcome are unchanged (still directly unit-tested) and are now invoked from the bridge.

No behavior change

This is a pure refactor. The UnitTestOutcome → VSTest TestOutcome mapping and the assembled TestResult (messages, attachments, error info, timings) are byte-for-byte equivalent, and every branch of the original SendTestResults flow is preserved: empty-results → RecordEnd(None); per result → RecordEnd(mapped), trace on Failed, _hasAnyTestFailed (under #if !WINDOWS_UWP && !WIN_UI), and the guarded RecordResult inside try/catch(TestCanceledException) with the NotFound + hot-reload skip.

Verification

  • build.cmd -c Debug green across all TFMs (net462, net8.0, net9.0, UWP, WinUI); analyzers-as-errors clean.
  • MSTestAdapter.PlatformServices.UnitTests (net8.0): 889 passed.
  • MSTestAdapter.UnitTests (net8.0): 21 passed.
  • expert-reviewer confirmed byte-for-byte equivalence of the refactored flow.

Relationship to other PRs

Independent of and parallel to #9548 (Phase 1). The diff is disjoint from Phase 1's production files. One Phase-1 test file (TestExecutionManagerTests.cs) is touched by a single line — the direct SendTestResults call now wraps _frameworkHandle.ToTestResultRecorder(...); this hunk is far from Phase 1's edits and should not conflict.

Introduce a platform-agnostic `ITestResultRecorder` so the execution result
path in PlatformServices no longer constructs VSTest result-side types
(`TestResult`, `TestOutcome`, `TestResultMessage`, `AttachmentSet`,
`UriDataAttachment`). The single VSTest translation point now lives in the
adapter-facing bridge `HostTestResultRecorder`
(`Services/TestResultRecorderExtensions.ToTestResultRecorder`), mirroring the
Phase 1 `IAdapterMessageLogger` + `AdapterMessageLoggerExtensions` pattern.

`TestExecutionManager.Runner.cs` routes start/empty/result reporting through the
neutral recorder. `TestResultExtensions.ToTestResult` and
`UnitTestOutcomeHelper.ToTestOutcome` are unchanged and are now called from the
bridge. This is a pure refactor with no behavior change: the outcome mapping,
assembled `TestResult`, and the trace / `_hasAnyTestFailed` / NotFound+HotReload
branches are preserved.

Independent of and parallel to PR #9548 (Phase 1).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 1, 2026 15:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR is Phase 5 of the effort to make MSTestAdapter.PlatformServices platform-agnostic by concentrating VSTest result-object-model usage into a single bridge and having the execution pipeline report results through a neutral abstraction.

Changes:

  • Introduces a new internal result-recording abstraction: ITestResultRecorder.
  • Adds a single VSTest bridge (TestResultRecorderExtensions / HostTestResultRecorder) that translates framework results into VSTest TestResult and forwards to ITestExecutionRecorder.
  • Refactors TestExecutionManager.Runner to record start/empty/result via ITestResultRecorder, and updates the relevant unit test call site.
Show a summary per file
File Description
test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Execution/TestExecutionManagerTests.cs Updates a direct SendTestResults call to pass an ITestResultRecorder wrapper instead of a raw VSTest recorder.
src/Adapter/MSTestAdapter.PlatformServices/Services/TestResultRecorderExtensions.cs Adds the single translation point from VSTest ITestExecutionRecorder to the platform-agnostic ITestResultRecorder.
src/Adapter/MSTestAdapter.PlatformServices/Interfaces/ITestResultRecorder.cs Introduces the new internal recorder interface used by PlatformServices to report execution lifecycle and results.
src/Adapter/MSTestAdapter.PlatformServices/Execution/TestExecutionManager.Runner.cs Switches result reporting from direct VSTest result-type construction to the new recorder abstraction.

Review details

  • Files reviewed: 4/4 changed files
  • Comments generated: 1
  • Review effort level: Low

Comment thread src/Adapter/MSTestAdapter.PlatformServices/Interfaces/ITestResultRecorder.cs Outdated
Address PR review: the concrete recorder is provided at the platform boundary by a wrapper over the host's ITestExecutionRecorder (currently TestResultRecorderExtensions in PlatformServices/Services), rather than by the 'adapter layer'. Doc-only change; no behavior change.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@Evangelink Evangelink merged commit 1a0a7e4 into main Jul 3, 2026
38 of 39 checks passed
@Evangelink Evangelink deleted the dev/amauryleve/abstract-vstest-results-platformservices branch July 3, 2026 09:31
Evangelink added a commit that referenced this pull request Jul 5, 2026
…ervices

Squashed rebase of the vstest-decoupling PlatformServices stack onto main.
Phases 1, 2 and 5 already landed on main via #9548/#9567/#9550; this commit
carries the remaining net-new work:

- Phase 3  (#9566): abstract the VSTest discovery sink (IUnitTestElementSink).
- Phase 4  (#9572): abstract VSTest execution input.
- Phase 6a (#9576): neutralize deployment input (DeploymentContext).
- Phase 6b (#9579): neutralize test result recording (ITestResultRecorder).
- Phase 6c (#9585): neutralize test message logging.
- Phase 6c2:         neutralize run-settings input in the host layer (settingsXml).
- Phase 6d-1:        move test-case filter parsing to the adapter boundary
                     (ITestElementFilterProvider / TestElementFilterProvider).
- Phase 6d-2:        remove IRunContext/IDiscoveryContext from PlatformServices.
- Phase 6e-1 (#9622): remove IFrameworkHandle from the execution engine.
- Phase 6e-2 (#9623): relocate VSTest logger/sink bridges to the adapter.
- Phase 6e-3a (#9624): neutralize the trait type on UnitTestElement.

Result: MSTestAdapter.PlatformServices no longer references the VSTest
run/discovery context or result object model; those types live only at the
MSTest.TestAdapter boundary.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Evangelink added a commit that referenced this pull request Jul 5, 2026
…ervices

Squashed rebase of the vstest-decoupling PlatformServices stack onto main.
Phases 1, 2 and 5 already landed on main via #9548/#9567/#9550; this commit
carries the remaining net-new work:

- Phase 3  (#9566): abstract the VSTest discovery sink (IUnitTestElementSink).
- Phase 4  (#9572): abstract VSTest execution input.
- Phase 6a (#9576): neutralize deployment input (DeploymentContext).
- Phase 6b (#9579): neutralize test result recording (ITestResultRecorder).
- Phase 6c (#9585): neutralize test message logging.
- Phase 6c2:         neutralize run-settings input in the host layer (settingsXml).
- Phase 6d-1:        move test-case filter parsing to the adapter boundary
                     (ITestElementFilterProvider / TestElementFilterProvider).
- Phase 6d-2:        remove IRunContext/IDiscoveryContext from PlatformServices.
- Phase 6e-1 (#9622): remove IFrameworkHandle from the execution engine.
- Phase 6e-2 (#9623): relocate VSTest logger/sink bridges to the adapter.
- Phase 6e-3a (#9624): neutralize the trait type on UnitTestElement.

Result: MSTestAdapter.PlatformServices no longer references the VSTest
run/discovery context or result object model; those types live only at the
MSTest.TestAdapter boundary.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-review Awaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants