From d093d872ae5a46e38c1602e93bab1c51a7495e18 Mon Sep 17 00:00:00 2001 From: gamer147 Date: Mon, 1 Jun 2026 00:06:47 -0400 Subject: [PATCH] test(unit-tests): parallelize at the fixture level MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- SVSim.UnitTests/AssemblyInfo.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 SVSim.UnitTests/AssemblyInfo.cs diff --git a/SVSim.UnitTests/AssemblyInfo.cs b/SVSim.UnitTests/AssemblyInfo.cs new file mode 100644 index 0000000..0ee0b9f --- /dev/null +++ b/SVSim.UnitTests/AssemblyInfo.cs @@ -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)] +