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):
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)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
SpikerSoft.Tests.Unithad 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>.Testsper source project that has tests, folder next to the source project, namespaces mirroring it (e.g.SpikerSoft.Business.Tests.Domain.Blog.Commands):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.slnfsolution filter = single test target for CI (tests.yml,sonar-scan.yml,run-tests.ps1all switched)using SpikerSoft.*imports (type-under-test wins on ties); packages per project derived from actual usage, so LLamaSharp/Aspose/Tesseract only load where neededInternalsVisibleTogrants rewritten from the monolith name to the consuming test assembliesVerification
dotnet test --list-tests= 11,435 on master and after the split (name-normalized diff is empty)dotnet build SpikerSoft.slngreen (includes IVT rewrites and Benchmarks)