Skip to content

Add C++/CLI + MSTest acceptance tests (VSTest and MTP)#9509

Merged
Evangelink merged 4 commits into
mainfrom
dev/amauryleve/cppcli-mstest-vstest-acceptance-test
Jun 30, 2026
Merged

Add C++/CLI + MSTest acceptance tests (VSTest and MTP)#9509
Evangelink merged 4 commits into
mainfrom
dev/amauryleve/cppcli-mstest-vstest-acceptance-test

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Why

Some internal teams still rely on the deprecated Microsoft::VisualStudio::CppUnitTestFramework (CppUnit). It's VSTest-bound and aimed at managed/mixed C++, so MSTest is a plausible migration target for the C++/CLI subset of those projects. These acceptance tests guard that scenario against accidental breakage as we move toward Microsoft.Testing.Platform (MTP).

What

Two Windows-only acceptance tests in MSTest.Acceptance.IntegrationTests, each building a tiny C++/CLI managed test assembly against the freshly-built MSTest packages and asserting the tests are discovered and executed:

  • CppCliVSTestTests — runs the C++/CLI assembly through vstest.console.exe + the just-built MSTest adapter (the legacy, VSTest-bound path).
  • CppCliMtpTests — hosts Microsoft.Testing.Platform from a C++/CLI Application with a managed main (CreateBuilderAsync/AddMSTest/BuildAsync/RunAsync), producing a self-contained MTP test host — no vstest.console needed.
  • CppCliTestSupport — shared helpers (locate a VS install with the MSVC toolset via vswhere; build a child-process environment with the code-coverage profiler variables stripped).

How they work

A C++/CLI .vcxproj cannot consume managed assemblies from a NuGet PackageReference, so:

  • the VSTest test extracts the packed MSTest.TestFramework/MSTest.TestAdapter and references the assemblies via <HintPath>;
  • the MTP test harvests the full MTP + MSTest net472 runtime closure by building a generated C# EnableMSTestRunner project (NuGet resolves the closure into its output), then deploys it next to the C++/CLI exe.

Both build the .vcxproj with full Visual Studio MSBuild (the dotnet SDK muxer can't build a .vcxproj).

Gating

Both are [OSCondition(OperatingSystems.Windows)] and skip (Assert.Inconclusive) when no Visual Studio install with the MSVC C++ toolset (Microsoft.VisualStudio.Component.VC.Tools.x86.x64) is present, so SDK-only build legs stay green. This is classic /clr (.NET Framework); /clr:netcore is a separate, untested axis.

Validation

.\build.cmd -pack then dotnet run --project test/IntegrationTests/MSTest.Acceptance.IntegrationTests -- --filter "FullyQualifiedName~CppCli"total: 2, succeeded: 2, skipped: 0 on a VS-equipped Windows machine.

Notes for reviewers

  • These tests only execute where the C++ toolset exists; elsewhere they self-skip. Worth deciding whether CI should run a C++/CLI-capable Windows leg so they actually exercise.
  • The MTP test demonstrates C++/CLI can be a first-class MTP host — a stronger, MTP-aligned migration target than the VSTest path. Happy to follow up with a small MSTest.CppCli helper package (header-only ergonomics layer + props/targets that deploy the closure) if there's appetite.

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

Evangelink and others added 2 commits June 29, 2026 17:06
Guards that MSTest test classes authored in a C++/CLI managed assembly are discovered and executed by the MSTest VSTest adapter. Windows-only and skipped (inconclusive) when the MSVC toolset is absent. Builds a tiny C++/CLI test assembly against the freshly-packed MSTest packages with VS MSBuild, then runs it via vstest.console with the just-built adapter.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds CppCliMtpTests guarding that MSTest tests authored in a C++/CLI managed assembly can be hosted on Microsoft.Testing.Platform as a self-contained test executable (no vstest.console). Harvests the MTP+MSTest net472 runtime closure via a generated C# EnableMSTestRunner project, builds the C++/CLI exe with VS MSBuild, deploys the closure, and asserts MTP discovers and runs the tests. Extracts shared gate/env helpers into CppCliTestSupport and reuses them from the existing VSTest test.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 29, 2026 19:17

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 adds two Windows-only MSTest acceptance tests that validate authoring MSTest tests in a managed C++/CLI assembly and running them via both legacy VSTest and Microsoft.Testing.Platform (MTP) hosting paths. It also introduces shared helper utilities to locate a VS install with the VC toolset and to sanitize child-process environments from code-coverage profiler variables.

Changes:

  • Add CppCliVSTestTests to build a generated C++/CLI test DLL and run it via vstest.console.exe using the freshly packed MSTest adapter.
  • Add CppCliMtpTests to build a C++/CLI MTP-hosted test EXE and run it as a self-contained MTP test host.
  • Add CppCliTestSupport helper for VS/toolset detection (via vswhere) and code-coverage env-var stripping for child processes.
Show a summary per file
File Description
test/IntegrationTests/MSTest.Acceptance.IntegrationTests/CppCliVSTestTests.cs New VSTest-path acceptance test that builds a C++/CLI MSTest DLL and validates discovery/execution via vstest.console.exe.
test/IntegrationTests/MSTest.Acceptance.IntegrationTests/CppCliMtpTests.cs New MTP-path acceptance test that harvests the net472 runtime closure, builds a C++/CLI MTP host EXE, and validates execution.
test/IntegrationTests/MSTest.Acceptance.IntegrationTests/CppCliTestSupport.cs Shared VS discovery + environment sanitization utilities used by both C++/CLI acceptance tests.

Review details

  • Files reviewed: 3/3 changed files
  • Comments generated: 5
  • Review effort level: Low

Comment thread test/IntegrationTests/MSTest.Acceptance.IntegrationTests/CppCliMtpTests.cs Outdated
Comment thread test/IntegrationTests/MSTest.Acceptance.IntegrationTests/CppCliVSTestTests.cs Outdated
@Evangelink

This comment has been minimized.

@Evangelink Evangelink left a comment

Copy link
Copy Markdown
Member Author

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

Expert Review — PR #9509 · Add C++/CLI + MSTest acceptance tests (VSTest and MTP)

# Dimension Verdict
12 Flakiness Patterns 🟡 1 MODERATE
15 Code Structure & Simplification 🔵 1 NIT

✅ 20/22 dimensions clean.

  • Flakiness — both vcxproj templates hardcode PlatformToolset=v143 (VS 2022 only), but the vswhere guard in TryFindVsInstallWithCppToolsetAsync accepts any VS that ships VC.Tools.x86.x64 (VS 2017+). A VS 2019-only machine passes the availability check but the MSBuild step errors out, reporting FAILED instead of Inconclusive. Fix: add -version "[17.0,)" to the vswhere query in CppCliTestSupport.
  • Code Structure (NIT)CodeCoverageEnvironmentVariables is a string[] iterated with LINQ Contains. A HashSet<string> with StringComparer.OrdinalIgnoreCase is more idiomatic and O(1).

Per-dimension notes

# Dimension Notes
1 Algorithmic Correctness ✅ Exit-code assertions include the full build/run output in the failure message. Null-guard pattern with Assert.Inconclusive + return is correct (the return is unreachable but defensive and matches codebase convention).
2 Threading & Concurrency ✅ Each test class has one test method; no shared mutable state. CommandLine manages its own process semaphore. C++/CLI Task.Result pattern in MtpHost.cpp is safe for a managed-entry-point console app with no SynchronizationContext.
3 Security & IPC ✅ All paths constructed via Path.Combine; no user-controlled data fed to shell arguments beyond the asset-generation pipeline that the rest of the acceptance suite already uses.
7 Resource Management ✅ All CommandLine, TestAsset, and TempDirectory instances are guarded by using. CancellationTokenRegistration in CommandLine.RunAsyncAndReturnExitCodeAsync is disposed via the using CancellationTokenRegistration statement.
8 Defensive Coding ✅ Both test methods assert exit codes with Assert.AreEqual(0, exitCode, $"...{output}..."), providing full diagnostic output on failure.
10 Test Isolation ✅ Each method creates its own TestAsset directory. Binlog filenames are unique per method; no shared mutable state across the two new test classes.
11 Assertion Quality ✅ Assertions match the repo convention: Assert.Contains for substring matching, Assert.AreEqual for exit codes, Assert.IsTrue(File.Exists(...)) with descriptive messages.
17 Documentation ✅ Class-level XML docs clearly explain the scenario, the NuGet-can't-resolve-in-vcxproj limitation, and the harvest workaround. Inline comments explain each numbered step.
21 Scope & PR Discipline ✅ Three new files, all test-only, all in the correct acceptance-test project. No production code touched.

Comment thread test/IntegrationTests/MSTest.Acceptance.IntegrationTests/CppCliMtpTests.cs Outdated
Comment thread test/IntegrationTests/MSTest.Acceptance.IntegrationTests/CppCliVSTestTests.cs Outdated
Comment thread test/IntegrationTests/MSTest.Acceptance.IntegrationTests/CppCliTestSupport.cs Outdated
- Derive MSBuild from the validated VS install (TryGetMSBuildPathFromVsInstall)
  instead of locating it independently, so the C++ targets/toolset are
  guaranteed available on multi-VS machines.
- Use the install's default platform toolset instead of hard-coded v143 so the
  tests work on any VS version with the VC toolset (not just VS2022). Omitting
  the toolset entirely defaults to v100 and fails, so the install default is
  selected explicitly via DefaultPlatformToolset.
- Self-skip (Inconclusive) when vstest.console.exe is absent from the located VS
  install (e.g. Build Tools without the Test Platform), matching the
  missing-toolset behavior.

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

This comment has been minimized.

Use a HashSet<string> with OrdinalIgnoreCase instead of a string[] + LINQ linear scan for the code-coverage environment variable filter (per review nit). IDE0028 is suppressed locally because a collection expression cannot carry the custom comparer.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 29, 2026 20:41
@Evangelink

Copy link
Copy Markdown
Member Author

🧪 Test quality grade — PR #9509

2 new integration tests graded across 2 files. Both earn A — they are well-structured end-to-end acceptance tests with numbered steps, meaningful intermediate assertions at each stage, and clean environment hygiene (code-coverage profiler variables stripped before spawning child processes). No issues found; these are good additions.

ΔTestGradeBandNotes
new CppCliMtpTests.
MSTestTestsInCppCliAssembly_
AreHostedAndRun_
ByMtp
A 90–100 Clear numbered steps; multiple assertions verify harvest, C++/CLI build, deployment, and MTP execution.
new CppCliVSTestTests.
MSTestTestsInCppCliAssembly_
AreDiscoveredAndRun_
ByVSTest
A 90–100 Multiple assertions verify NuGet extraction, C++/CLI build, and VSTest execution; good environment hygiene.

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. 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 Grade Tests on PR (on open / sync) workflow. · 336.2 AIC · ⌖ 13.9 AIC · ⊞ 43.7K · [◷]( · )

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.

Review details

  • Files reviewed: 3/3 changed files
  • Comments generated: 0 new
  • Review effort level: Low

@Evangelink
Evangelink enabled auto-merge (squash) June 30, 2026 05:02
@Evangelink Evangelink added the state/needs-review Awaiting review from the team. label Jun 30, 2026
@Evangelink
Evangelink merged commit 4fd64bc into main Jun 30, 2026
38 checks passed
@Evangelink
Evangelink deleted the dev/amauryleve/cppcli-mstest-vstest-acceptance-test branch June 30, 2026 08:20
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