Abstract VSTest discovery sink in PlatformServices (Phase 3 of platform-agnostic effort)#9625
Conversation
…rm-agnostic effort) (#9566) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR delivers Phase 3 of the ongoing effort to make MSTestAdapter.PlatformServices platform-agnostic by removing its dependency on the VSTest object model. It abstracts the discovery output sink: the discovery engine (UnitTestDiscoverer) now emits the neutral UnitTestElement model to a new IUnitTestElementSink instead of building VSTest TestCases and pushing them to ITestCaseDiscoverySink. The single element.ToTestCase() translation moves behind a Services/ bridge, wrapped once at the adapter boundary in MSTestDiscoverer. This mirrors the already-merged Phase 1 (IAdapterMessageLogger), Phase 5 (ITestResultRecorder), and Phase 2 (ITestElementFilter) interface+bridge conventions. It is described as a pure, no-behavior-change refactor.
Changes:
- Introduces neutral
IUnitTestElementSink(SendTestElement(UnitTestElement)) plus theUnitTestElementSinkExtensions.ToUnitTestElementSink()bridge that materializesTestCaseat the VSTest boundary. - Migrates
UnitTestDiscoverer(DiscoverTests/DiscoverTestsInSource/SendTestCases) and the execution-sideTestCaseDiscoverySinkto the neutral sink;MSTestDiscovererwraps the host sink at the boundary. - Updates unit/integration tests to wrap mocked
ITestCaseDiscoverySinkvia.ToUnitTestElementSink()and rewritesTestCaseDiscoverySinkTestsfor the new API.
Show a summary per file
| File | Description |
|---|---|
src/Adapter/MSTestAdapter.PlatformServices/Interfaces/IUnitTestElementSink.cs |
New neutral discovery sink interface (mirrors Phase 1/2/5 interface placement/namespace). |
src/Adapter/MSTestAdapter.PlatformServices/Services/UnitTestElementSinkExtensions.cs |
New single VSTest bridge wrapping ITestCaseDiscoverySink, materializing TestCase via ToTestCase(). |
src/Adapter/MSTestAdapter.PlatformServices/Discovery/UnitTestDiscoverer.cs |
Discovery engine now takes/emits IUnitTestElementSink; no longer references ITestCaseDiscoverySink or ToTestCase(). |
src/Adapter/MSTestAdapter.PlatformServices/Execution/TestCaseDiscoverySink.cs |
Execution collector now implements IUnitTestElementSink, still materializing TestCase internally. |
src/Adapter/MSTest.TestAdapter/VSTestAdapter/MSTestDiscoverer.cs |
Adapter boundary wraps the host sink via .ToUnitTestElementSink(). |
test/.../Discovery/UnitTestDiscovererTests.cs |
Call sites wrap the mocked sink; test override uses the new sink API. |
test/.../Execution/TestCaseDiscoverySinkTests.cs |
Rewritten to assert SendTestElement materialization and ordering. |
test/.../Utilities/CLITestBase.discovery.cs |
Integration helper wraps its internal sink before calling discovery. |
Review details
- Files reviewed: 8/8 changed files
- Comments generated: 0
- Review effort level: Medium
There was a problem hiding this comment.
Note
🤖 Automated review by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.
✅ 22/22 dimensions clean — no findings.
Summary: Clean mechanical refactoring that introduces IUnitTestElementSink + UnitTestElementSinkExtensions following the exact same interface-plus-bridge pattern established in Phase 1 (IAdapterMessageLogger / AdapterMessageLoggerExtensions) and Phase 2 (ITestResultRecorder / TestResultRecorderExtensions). All new types are internal, no public API surface change, no behavioral change, tests properly updated to verify materialization through the new abstraction. The removal of the old null-accepting SendTestCase(TestCase?) in favor of non-nullable SendTestElement(UnitTestElement) is correct since the C# type system enforces the contract. Thread safety is maintained — TestCaseDiscoverySink is used sequentially per-source in the execution loop.
🧪 Test quality grade — PR #9625
This advisory comment was generated automatically. Grades are heuristic
|
Why
Continues the platform-agnostic PlatformServices effort. Phase 1 (#9548), Phase 2 (#9567), and Phase 5 (#9550) are on
main; this brings Phase 3 (discovery sink) tomain.Same change previously reviewed and merged as #9566 (into the integration branch
dev/amauryleve/vstest-decoupling-base). Cherry-picked cleanly onto currentmainas a standalone, Phase-3-only PR now that its prerequisite (Phase 2) has landed.What
The discovery engine (
UnitTestDiscoverer) now emits the neutralUnitTestElementto a new platform-agnosticIUnitTestElementSink(SendTestElement(UnitTestElement)) instead of building VSTestTestCases and pushing toITestCaseDiscoverySink. The singleelement.ToTestCase()translation moves behind the boundary via aServices/bridge (UnitTestElementSinkExtensions.ToUnitTestElementSink(this ITestCaseDiscoverySink)), wrapped at the adapter boundary inMSTestDiscoverer. Mirrors the Phase 1/2/5 interface + bridge convention.The internal execution-side collector
TestCaseDiscoverySinknow implementsIUnitTestElementSinkbut still materializesTestCaseinto itsICollection<TestCase> Tests, so execution behaves identically.No behavior change
Pure refactor — byte-for-byte identical discovered
TestCases (fields,Id, properties, traits, ordering), filter point, andfilterHasErrorbail-out.Verification
Cherry-picked cleanly onto current
main; PlatformServices + its unit-test project rebuild with 0 errors/0 warnings on the new base. (Originally verified green across all TFMs + full unit/integration suites as #9566.)