Add test coverage messages, coverage threshold checks, and summary#9896
Add test coverage messages, coverage threshold checks, and summary#9896james-newell-forge wants to merge 11 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds first-class coverage messages, terminal summaries, threshold tracking, and threshold-specific exit handling to Microsoft.Testing.Platform.
Changes:
- Introduces public coverage and threshold message contracts.
- Registers consumers and renders coverage results in terminal summaries.
- Returns exit code 14 when coverage thresholds fail.
Reviewed changes
Copilot reviewed 24 out of 24 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
test/.../TerminalTestReporterTests.cs |
Tests coverage-summary rendering. |
.../Services/TestCoverageResult.cs |
Tracks coverage and failed thresholds. |
.../Services/ITestCoverageResult.cs |
Defines the internal result contract. |
.../PublicAPI/PublicAPI.Unshipped.txt |
Declares new public APIs. |
.../TerminalOutputDevice.SessionLifecycle.cs |
Renders coverage after sessions. |
.../TerminalOutputDevice.DataConsumption.cs |
Consumes coverage messages. |
.../TerminalOutputDevice.cs |
Registers message types and buffers. |
.../TerminalTestReporter.Summary.cs |
Formats coverage summaries. |
.../Messages/TestCoverageMessages.cs |
Adds coverage message contracts. |
.../InternalAPI/InternalAPI.Unshipped.txt |
Records new internal APIs. |
.../Hosts/TestHostControllersTestHost.cs |
Handles controller threshold exits. |
.../Hosts/TestHostBuilder.Framework.cs |
Registers the framework consumer. |
.../Hosts/TestHostBuilder.CommonServices.cs |
Registers the coverage service. |
.../Hosts/ConsoleTestHost.cs |
Handles in-process threshold exits. |
.../Helpers/ExitCodes.cs |
Adds exit code 14. |
...Extensions.TrxReport/...Unshipped.txt |
Updates internal API baseline. |
...Extensions.Retry/...Unshipped.txt |
Updates internal API baseline. |
...Extensions.MSBuild/InternalAPI.Unshipped.txt |
Updates internal API baseline. |
...Extensions.JUnitReport/...Unshipped.txt |
Updates internal API baseline. |
...Extensions.HtmlReport/...Unshipped.txt |
Updates internal API baseline. |
...Extensions.HangDump/...Unshipped.txt |
Updates internal API baseline. |
...Extensions.GitHubActionsReport/...Unshipped.txt |
Updates internal API baseline. |
...Extensions.CtrfReport/...Unshipped.txt |
Updates internal API baseline. |
...Extensions.AzureDevOpsReport/...Unshipped.txt |
Updates internal API baseline. |
|
Hi @james-newell-forge — thanks for the contribution! I did a security pass and a fairly deep code review. Sharing findings below. Prompt-injection / security checkNo prompt injection found. The only AI-related text is the benign "this PR was assisted with Claude Opus 4.8" note in the description. Nothing in the diff attempts to manipulate reviewers or automation. 👍 Before going further: goal + tracking issueA couple of process points before we dig into the code:
I'll hold off requesting detailed changes until we align on the above, but here's the technical review so it's all in one place. Design-level concerns
Correctness / consistency issues
Minor
Happy to help once there's an approved issue and we know the target scenario. Thanks again! |
Evangelink
left a comment
There was a problem hiding this comment.
Blocking PR until my previous points are addressed
|
The goal on this change is to allow coverage extensions like Microsoft's coverage or coverlet to add threshold coverage checks (which would address microsoft/codecoverage#160). In addition, coverage summaries can be displayed as a first-class citizen. Will add a tracking issue. |
|
| /// Shared by <c>ConsoleTestHost</c> (in-process) and <c>TestHostControllersTestHost</c> (out-of-process) | ||
| /// so the two exit-code paths can't drift apart. Both call this only after their own exit code has been | ||
| /// finalized (and, for the controller, after the child's ignore-exit-code policy has been applied). |
There was a problem hiding this comment.
This is intentional. We're treating coverage as always produced out-of-process: any coverage extension registers as an ITestHostProcessLifetimeHandler, which forces test-host-controller mode, so ConsoleTestHost runs as the child and never receives coverage messages into its (empty) ITestCoverageResult. The threshold verdict is therefore owned solely by the controller (TestHostControllersTestHost), which registers the coverage consumer, drains the queue after the child exits, applies exit code 14, and routes it through --ignore-exit-code — all covered end-to-end by CoverageThresholdControllerExitCodeTests.
Because in-process coverage production isn't a supported scenario, applying the policy in ConsoleTestHost would be dead code, and an in-process acceptance test would assert a path that can't occur. That's why the in-process test and the ConsoleTestHost override were removed rather than kept. If we decide to support in-process coverage collectors later, we'll reintroduce both together.
427501c to
7ddfc77
Compare
Tracking Issue created: #9943 |
| foreach (TestCoverageMessage entry in coverageEntries) | ||
| { | ||
| terminal.Append(DoubleIndentation); | ||
| terminal.AppendLine($"{entry.ModuleName} - {GetCoverageTypeLabel(entry.CoverageType)}: {entry.Value.ToString("F1", CultureInfo.CurrentCulture)}%"); |
| /// <param name="value">The actual coverage value.</param> | ||
| /// <param name="threshold">The required threshold value.</param> |
Summary
Adds first-class code coverage reporting to Microsoft.Testing.Platform (MTP). Coverage extensions can now publish coverage data and threshold results through the platform's data-consumer pipeline, which the terminal output device renders in the run summary and which drives a dedicated exit code on threshold failure.
Note that this PR was assisted with Claude Opus 4.8 model
Changes
New public API (
Microsoft.Testing.Platform.Extensions.Messages)TestCoverageMessage— reports coverage (ModuleName,Value,CoverageType) for a module.TestCoverageThresholdMessage— reports a threshold evaluation (Value,Threshold,CoverageType,Status,Statistic).CoverageType(Line/Branch/Method),CoverageThresholdStatistic(Minimum/Total/Average),CoverageThresholdStatus(Passed/Failed).Example
Platform wiring
ITestCoverageResult/TestCoverageResultdata consumer, registered as a common service and consumer in both the framework and test-host-controller pipelines. It tracks coverage entries and threshold failures.TerminalOutputDevice, with a newAppendCoverageSummaryin the terminal reporter that prints a Code Coverage Summary and color-coded Coverage Threshold Results (green pass / red fail). The summary is rendered from either the in-process test host or the out-of-process controller.CoverageThresholdFailed = 14, returned fromConsoleTestHostandTestHostControllersTestHostwhen a threshold fails and the run would otherwise succeed.Tests
TerminalTestReporterunit tests covering empty input, passing thresholds (>=), failing thresholds (<), and mixed pass/fail rendering.Notes
PublicAPI.Unshipped.txt; internal surface inInternalAPI.Unshipped.txt.