Skip to content

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: WebApplicationFactory for 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). No Test prefix.
  • 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/getByLabelText per the official query priority; reach for getByTestId last.
  • 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