Set NUnit and Assert.That as the testing standard in CLAUDE.md

Replaces xUnit + FluentAssertions with NUnit, asserting through Assert.That and
the constraint model. Adds concrete examples for the shapes that come up most
here — collection equality, null checks, expected exceptions — plus a note on
Assert.Multiple, since a plain chain stops at the first failure and hides the
rest of a broken case.

Documentation only. The existing 44 tests are still xUnit + FluentAssertions and
now predate the standard; migrating them is a separate change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S56bfZMGe1hnhpWP4CjjNw
This commit is contained in:
James Wampler
2026-08-06 12:11:20 -07:00
co-authored by Claude Opus 5
parent 1852ceb2d1
commit 8394843255
+5 -1
View File
@@ -49,7 +49,11 @@ Novel Software: software for planning and writing a novel. ASP.NET Core 10, C#,
- Don't write tests just for coverage. Call out missing coverage rather than cover stuff not valuable to end user. - Don't write tests just for coverage. Call out missing coverage rather than cover stuff not valuable to end user.
- Code not cleanly unit-testable → mark `[ExcludeFromCodeCoverage]` or exclude namespace from coverage in .runsettings file - Code not cleanly unit-testable → mark `[ExcludeFromCodeCoverage]` or exclude namespace from coverage in .runsettings file
- BDD-style unit tests, end-to-end as possible. e.g. `Deleting_a_scene_leaves_its_beats_alone` - BDD-style unit tests, end-to-end as possible. e.g. `Deleting_a_scene_leaves_its_beats_alone`
- xUnit + FluentAssertions - NUnit. No FluentAssertions — assert with `Assert.That` and NUnit's constraint model:
`Assert.That(beat.SceneId, Is.Null)`, `Assert.That(listed, Has.Count.EqualTo(3))`,
`Assert.That(titles, Is.EqualTo(new[] { "First", "Second" }))`
- Grouping related asserts in `Assert.Multiple` beats a chain that stops at the first failure
- Expected exceptions: `Assert.That(() => service.Foo(), Throws.TypeOf<NotFoundException>())`
- Tests run against real in-memory SQLite via `TestDatabase`, not the EF InMemory provider — cascade deletes and query translation must be exercised, and the InMemory provider fakes both - Tests run against real in-memory SQLite via `TestDatabase`, not the EF InMemory provider — cascade deletes and query translation must be exercised, and the InMemory provider fakes both
- Model calls are faked at the `IAgentModelClient` seam (see `ScriptedModelClient`). Never hit the Anthropic API from a test. - Model calls are faked at the `IAgentModelClient` seam (see `ScriptedModelClient`). Never hit the Anthropic API from a test.
- No "Mock" in mocked object names - No "Mock" in mocked object names