Skip to content

test: use latestMajor roll-forward in tests that build real projects - #258

Open
samtrion wants to merge 4 commits into
mainfrom
fix/stryker-sdk-8-0-204-missing-in-stryker-container-a1
Open

samtrion wants to merge 4 commits into
mainfrom
fix/stryker-sdk-8-0-204-missing-in-stryker-container-a1

Conversation

@samtrion

@samtrion samtrion commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Problem

In the scheduled mutation run the initial test run reports 16 tests are failing, 14 tests are failing and 30 tests are failing. Stryker will continue but outcome will be impacted., followed by 51 Mutant N is only covered by failing tests lines. Run 40488203974 (TUnit test report artifact 12728695723) shows 16 failing tests, all with FileNotFoundException '.../result.sarif'; the captured stderr in that artifact (not in the job log) says A compatible .NET SDK was not found. Requested SDK version: 8.0.204 ... Installed SDKs: (empty). The mutation report has 40 mutants Survived with reason "Only covered by already failing tests" plus about 16 more NoCoverage mutants in the same code (ProjectFactory, ProjectFactoryExtensions, GlobalJsonBuilderExtensions, TestPackageBuilder).

Root cause

The integration tests that restore/build a generated project write a global.json pinning SDK 8.0.204 with rollForward: latestMinor. The shared mutation pipeline runs lyndychivs/dotnet-stryker-action in a Docker image based on mcr.microsoft.com/dotnet/sdk:10.0, which only has SDK 10.x. SDK 10 does not satisfy 8.0.204/latestMinor, so dotnet fails, result.sarif is never written and the test fails. The same tests pass in cicd.yml, which installs the needed SDKs via setup-dotnet. The 14 XUnit failures are assumed to share this cause; only the TUnit artifact was decoded, and the run on this branch verifies that.

Change

Test-side only: the tests that build real projects now use rollForward: latestMajor (ProjectFactoryTests, TestPackageBuilderTests, and the CSharp/VB BuildAsync_* tests in both integration projects). The CSharp/VB VerifyDirectory snapshots (global.verified.json) are updated from latestMinor to latestMajor. The public default (Constants.RuntimeSdkDefault, WithDefaults() = latestMinor) and the GlobalJsonBuilder snapshots are unchanged.

A fix in dailydevops/pipelines (provide SDK 8/9 to the mutation job) would address the cause for all repos but would mean replacing the shared Docker action, which is a larger cross-repo change; this PR is the small repo-local alternative.

Before / After

Measured with a manual mutation.yml dispatch on this branch (commit e0a086d, before the formatting-only follow-up): https://github.com/dailydevops/projectbuilders/actions/runs/40810054858 (before: the latest successful scheduled run, 2026-10-27).

metric before after
failing initial tests (TUnit IT + XUnit IT) 30 (16 + 14) 2 (1 + 1)
"Survived: only covered by failing tests" 40 0
"Mutant N is only covered by failing tests" log lines 51 0
NoCoverage mutants 27 11
Killed / Timeout / Survived (final report) 349 / 0 / 51 395 / 28 / 33
mutation score 74.73% 90.58%
mutants created 603 603
duration (Stryker "Time Elapsed") 00:09:09 01:31:36

Notes: the environment no longer deflates the score, but runtime grew about 10x because every covered mutant now runs a real restore and build. The 28 Timeout mutants count as detected. Two tests still fail in the initial run (one per integration project, not yet analysed); the cause is not confirmed to be the SDK. The mutation job still passes.

Risk / what this does not change

  • Weaker test: with latestMajor these builds run on whichever SDK is newest, so they no longer prove that an 8.0.x SDK specifically works. WithDefaults() output itself is still covered by the unit tests and GlobalJsonBuilder snapshots.
  • Once the tests pass, every covered mutant triggers a real restore and build, so the run will take considerably longer and some mutants may end up Timeout or Survived. Real numbers are measured on this branch.
  • Does not change the pipeline or the Stryker configuration.

The integration tests that restore and build a generated project write a
global.json pinning SDK 8.0.204 with rollForward latestMinor. The Stryker
container (mcr.microsoft.com/dotnet/sdk:10.0) only ships SDK 10.x, so
dotnet exits with "A compatible .NET SDK was not found", never writes
result.sarif and 30 initial tests fail. Their mutants are then reported
as only covered by failing tests.

Use latestMajor in the test-side global.json for those builds so any
installed SDK >= 8.0.204 satisfies it. The public default in Constants and
WithDefaults is unchanged; the CSharp/VB VerifyDirectory snapshots are
updated accordingly.
CS1998 for an async void Main without await is no longer reported by the
SDK 10 compiler, which latestMajor roll-forward now selects. Use an unused
local (CS0168) so the expected-warning case holds on every SDK.
@codecov

codecov Bot commented Oct 29, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.69%. Comparing base (3375b9a) to head (77042d8).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #258   +/-   ##
=======================================
  Coverage   89.69%   89.69%           
=======================================
  Files          31       31           
  Lines         728      728           
  Branches       85       85           
=======================================
  Hits          653      653           
  Misses         67       67           
  Partials        8        8           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant