test(unit-tests): parallelize at the fixture level

NUnit's default ParallelScope is Self (serial). With ~736 tests each
constructing its own SVSimTestFactory (full ASP.NET host + SQLite :memory:
+ ReferenceDataImporter seeding 7270 rows from CSVs), the suite was
running ~2m13s serial. ParallelScope.Fixtures drops it to ~1m46s — a
~20% wall-clock reduction with zero new failures.

Stayed at Fixtures rather than All because ParallelScope.All exposes
the process-static BattlePassRepository._curveCache (and likely other
similar caches) to races inside heavy-globals fixtures (LoadController,
PackControllerFullCatalog, StoryService — all consistent failures
under All, flaky 3-7 fails across runs). Within-fixture parallelism
is blocked on cleaning those up first.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-06-01 00:06:47 -04:00
parent 905fdc780a
commit d093d872ae

View File

@@ -0,0 +1,15 @@
using NUnit.Framework;
// Parallelize at the fixture level: different test classes run on separate threads, but tests
// inside one class still execute serially. Each fixture's SVSimTestFactory owns a private
// SQLite :memory: connection, so DB state isn't shared. Process-static caches (e.g.
// BattlePassRepository._curveCache) hold identical data across factories because every test
// seeds from the same JSON, so cross-fixture races on them are data-equivalent.
// Different test classes run on separate threads, but tests inside one class stay serial. Each
// fixture's SVSimTestFactory owns a private SQLite :memory: connection, so DB state isn't shared.
// ParallelScope.All is unsafe today: it exposes process-static caches (BattlePassRepository
// ._curveCache and similar) to races inside heavy-globals fixtures (LoadController,
// PackControllerFullCatalog, StoryService), so within-fixture parallelism is gated on cleaning
// those up first.
[assembly: Parallelizable(ParallelScope.Fixtures)]