Testing Standard¶
v1.0 — 2026-06-06 — NUnit 4 (4.6.1) + Moq (via ExpertGroup.Core.Testing) for .NET; Jest/Karma per frontend stack. For EF query-shape tests use ExpertGroup.Core.Testing.Ef (EfQueryAssert.MaxQueriesAsync) — see docs/testing-query-counting.md in the ExpertGroup repo.
Strategy (pragmatic pyramid)¶
- Broad unit base for business logic.
- Meaningful integration layer:
WebApplicationFactoryfor APIs; real SQL via Testcontainers or SQLite — never the EF InMemory provider for integration confidence. - Thin E2E for critical business flows only.
Rules¶
- Arrange-Act-Assert; one logical assertion per test; no logic (if/loops) in tests.
- Naming:
MethodUnderTest_Scenario_ExpectedBehavior(e.g.Calculate_NegativeAmount_ThrowsArgumentException). NoTestprefix. - Tests are Fast, Isolated, Repeatable, Self-checking, Timely — no shared mutable state, no order dependence, no real external services in unit tests.
- Prefer simple fakes over mock-everything setups; mock only true external boundaries.
Frontend testing (Angular & React)¶
Added from expert review (item 26: Dodds — Testing Trophy):
- Budget by the Testing Trophy, not the pyramid: static analysis (TS strict + ESLint) > some unit tests > a large integration layer > few E2E. Most frontend confidence comes from integration tests of components with their template/children rendered.
- Use Testing Library (Angular Testing Library / React Testing Library) with user-centric queries — prefer
getByRole/getByLabelTextper the official query priority; reach forgetByTestIdlast. - Never test implementation details — internal component state, private methods, or "was this service method called" assertions break on every refactor while proving nothing; test what the user sees and does.
- Guiding principle: "the more your tests resemble the way your software is used, the more confidence they can give you."
- Mock at the network boundary with MSW (item 27, accepted 2026-06-06) — Mock Service Worker intercepts actual requests instead of stubbing fetch/HttpClient wrappers/Apollo internals; the frontend parallel of "real SQL, never EF InMemory". Works for Apollo GraphQL (Angular apps) and Next.js fetch (Transfera); the same handler definitions double as local-dev mocks against unfinished backends.
Coverage¶
- By criticality, not blanket: ~80–90% business logic, ~70% infrastructure, 0% generated code. No 100% mandates.
- CI collects coverage (
dotnet test --collect:"XPlat Code Coverage") and publishes it. - Hard pipeline gate with −5 pp tolerance: a PR fails the build only if it drops coverage of a touched project by more than 5 percentage points versus the target branch; drops within that margin pass (allows legitimate refactors that delete covered code). Reviewers should still question any visible drop.
Definition of done¶
New behavior ships with tests; bug fixes ship with a regression test that fails without the fix.
Sources: MS unit testing best practices · Practical test pyramid · EF testing strategy