Decompose SpikerSoft.Tests.Unit into live-along per-project test projects #478

Closed
opened 2026-07-11 14:51:10 +00:00 by spikerj · 0 comments
Owner

Problem

SpikerSoft.Tests.Unit had grown into a monolith: 765 files / 11,435 unit tests in a single assembly referencing ~32 source projects and every heavy NuGet (LLamaSharp CUDA, Aspose.PDF, Tesseract, ...). It also doubled as the BenchmarkDotNet host (OutputType=Exe + StartupObject), which every IDE test run had to drag along. Test Explorer discovery, incremental builds and per-area CI triggers all paid for the whole world on every change.

Change

Big-bang decomposition (one PR) into live-along test projects — one SpikerSoft.<Project>.Tests per source project that has tests, folder next to the source project, namespaces mirroring it (e.g. SpikerSoft.Business.Tests.Domain.Blog.Commands):

  • 25 test projects (API, Business, Data, Common, GameServer, 15 EventHandlers., 3 Workers.)
  • SpikerSoft.Tests.Shared — shared helpers (MockDbSetHelper, SpikerDbContextTestOptions, FakeMongoClientWrapper, BookCommandTestContext) as a plain class library (IsTestProject=false)
  • SpikerSoft.Benchmarks — BenchmarkProgram + all BenchmarkDotNet classes moved out of test land into a plain console app (kills the Exe/StartupObject hack)
  • SpikerSoft.UnitTests.slnf solution filter = single test target for CI (tests.yml, sonar-scan.yml, run-tests.ps1 all switched)
  • Files classified by their using SpikerSoft.* imports (type-under-test wins on ties); packages per project derived from actual usage, so LLamaSharp/Aspose/Tesseract only load where needed
  • InternalsVisibleTo grants rewritten from the monolith name to the consuming test assemblies

Verification

  • Test-count parity: dotnet test --list-tests = 11,435 on master and after the split (name-normalized diff is empty)
  • Full run green: 25/25 projects, 11,453 executed (runtime theory expansion), 0 failed, exit 0
  • dotnet build SpikerSoft.sln green (includes IVT rewrites and Benchmarks)
## Problem `SpikerSoft.Tests.Unit` had grown into a monolith: 765 files / 11,435 unit tests in a single assembly referencing ~32 source projects and every heavy NuGet (LLamaSharp CUDA, Aspose.PDF, Tesseract, ...). It also doubled as the BenchmarkDotNet host (`OutputType=Exe` + `StartupObject`), which every IDE test run had to drag along. Test Explorer discovery, incremental builds and per-area CI triggers all paid for the whole world on every change. ## Change Big-bang decomposition (one PR) into **live-along test projects** — one `SpikerSoft.<Project>.Tests` per source project that has tests, folder next to the source project, namespaces mirroring it (e.g. `SpikerSoft.Business.Tests.Domain.Blog.Commands`): - 25 test projects (API, Business, Data, Common, GameServer, 15 EventHandlers.*, 3 Workers.*) - `SpikerSoft.Tests.Shared` — shared helpers (MockDbSetHelper, SpikerDbContextTestOptions, FakeMongoClientWrapper, BookCommandTestContext) as a plain class library (`IsTestProject=false`) - `SpikerSoft.Benchmarks` — BenchmarkProgram + all BenchmarkDotNet classes moved out of test land into a plain console app (kills the Exe/StartupObject hack) - `SpikerSoft.UnitTests.slnf` solution filter = single test target for CI (`tests.yml`, `sonar-scan.yml`, `run-tests.ps1` all switched) - Files classified by their `using SpikerSoft.*` imports (type-under-test wins on ties); packages per project derived from actual usage, so LLamaSharp/Aspose/Tesseract only load where needed - `InternalsVisibleTo` grants rewritten from the monolith name to the consuming test assemblies ## Verification - Test-count parity: `dotnet test --list-tests` = **11,435 on master and after the split** (name-normalized diff is empty) - Full run green: 25/25 projects, 11,453 executed (runtime theory expansion), 0 failed, exit 0 - `dotnet build SpikerSoft.sln` green (includes IVT rewrites and Benchmarks)
Sign in to join this conversation.