diff --git a/SVSim.UnitTests/Story/StoryServiceTests.cs b/SVSim.UnitTests/Story/StoryServiceTests.cs index 7e1e20a..1599ad5 100644 --- a/SVSim.UnitTests/Story/StoryServiceTests.cs +++ b/SVSim.UnitTests/Story/StoryServiceTests.cs @@ -16,6 +16,11 @@ using SVSim.UnitTests.Infrastructure; namespace SVSim.UnitTests.Story; [TestFixture] +// One instance per test case so parallel tests don't race on the SetUp-initialised +// _master / _viewer / _service fields. NUnit's default SingleInstance shares the +// fixture instance across all tests in the class; under ParallelScope.All, concurrent +// SetUps wipe each other's Mock setups and we see NullReferenceExceptions in service code. +[FixtureLifeCycle(LifeCycle.InstancePerTestCase)] public class StoryServiceTests { private Mock _master = null!; @@ -829,12 +834,15 @@ internal static class StoryServiceTestHelpers /// /// Returns a minimal backed by the EF InMemory provider. /// Safe for non-reward tests that never actually query the DB. - /// Each call should use a unique to prevent test bleed-through. + /// The supplied is suffixed with a fresh Guid so concurrent + /// callers never share a database — EF InMemory keys by name, and the previous callers + /// all passed the literal string "SetUp" via nameof(SetUp), which collapsed every + /// test in the fixture onto the same store and broke under parallel execution. /// public static SVSimDbContext NewInMemoryDb(string dbName) { var options = new Microsoft.EntityFrameworkCore.DbContextOptionsBuilder() - .UseInMemoryDatabase(dbName) + .UseInMemoryDatabase($"{dbName}-{Guid.NewGuid():N}") .Options; return new SVSimDbContext( Microsoft.Extensions.Logging.Abstractions.NullLogger.Instance,