Skip to content

Improve SourceGeneratorTests test speed.#12911

Merged
chsienki merged 1 commit intodotnet:mainfrom
chsienki:test_speed
Mar 18, 2026
Merged

Improve SourceGeneratorTests test speed.#12911
chsienki merged 1 commit intodotnet:mainfrom
chsienki:test_speed

Conversation

@chsienki
Copy link
Member

@chsienki chsienki commented Mar 18, 2026

Summary

Cache the fully-constructed base Project in source generator tests so it is built once and shared across all ~85 test invocations, reducing test execution time by ~60%.

Problem

CreateBaseProject() was called per-test, each time independently:

  • Loading DependencyContext via reflection
  • Scanning 200+ DLLs via Directory.EnumerateFiles
  • Creating MetadataReference.CreateFromFile() for each DLL
  • Performing O(n²) dedup via .Any() on all existing references
  • Adding references one-at-a-time, creating new immutable Solution snapshots per add

The resulting reference set was identical every time.

Fix

  • Cache the entire base Project (workspace, compilation options, parse options, and all metadata references) in a static Lazy<Project>. Since Project is immutable, every AddDocument/AddAdditionalDocument call in individual tests returns a new fork without affecting the shared instance.
  • The 2 tests that need custom CSharpParseOptions fork via WithParseOptions().
  • Replace the O(n²) dedup loop (.Any() per DLL) with Dictionary.TryAdd for O(1) lookups during the one-time initialization.

Results

Metric Before After
Total time (incl. build) ~51s ~20s

The CreateBaseProject method was called per-test (~85 times), each time
independently loading DependencyContext, scanning 200+ DLLs, performing
O(n²) dedup checks, and creating MetadataReference objects for the same
identical reference set.

Cache the fully-constructed base Project in a static Lazy<Project>. Since
Project is immutable, all test mutations (AddDocument, AddAdditionalDocument)
return new forks without affecting the shared instance. The two tests that
need custom CSharpParseOptions fork via WithParseOptions().

Also replaces the O(n²) dedup loop (.Any() per DLL) with Dictionary.TryAdd
for O(1) lookups during the one-time initialization.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@chsienki chsienki requested a review from a team as a code owner March 18, 2026 01:22
@chsienki chsienki changed the title Cache base project in source generator tests for ~60% speedup Improve SourceGenerator test speed. Mar 18, 2026
@chsienki chsienki changed the title Improve SourceGenerator test speed. Improve SourceGeneratorTests test speed. Mar 18, 2026
@chsienki chsienki merged commit 57eaac5 into dotnet:main Mar 18, 2026
10 checks passed
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Mar 18, 2026
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.

2 participants