Skip to content

Testing strategy: unit, integration and where test doubles belong #37

Description

@elgorro

Today there is one test project, tests/Ssabba.Domain.Tests (~190 lines), against roughly 19k lines
of source. Everything outside Ssabba.DomainMatchQueries / MatchEndpoints.cs, the EF
configurations, the client components — is untested, and there is nowhere to put such a test.

#34 and #30 each ask for a slice of testing but neither says what the layers are or where test
doubles are allowed. This issue writes that down once so the others slot into it.

Layers

  • Domain unit teststests/Ssabba.Domain.Tests, exists. Rating maths and entity invariants.
    Ssabba.Domain has no dependencies by construction, so there is nothing to substitute here.
  • Infrastructure / integration tests — new tests/Ssabba.Infrastructure.Tests. Real Postgres via
    Testcontainers with the migrations applied. Covers SsabbaDbContext, the
    IEntityTypeConfigurations and MatchQueries. This is the project Integration test for the rating write path #34 needs.
  • Web / API tests — new tests/Ssabba.Web.Tests. WebApplicationFactory over the minimal API
    under /api, authentication replaced by a test handler, database pointed at the same container.
  • Smoke test — the stack coming up in CI, scoped by End-to-end smoke test in CI #30. Not duplicated here.

Mocking: minimal, and no mocking library

Stated as policy so it is not re-argued per pull request.

  • No mocking framework is added. The Testing group in Directory.Packages.props keeps
    xunit.v3, Test.Sdk, runner.visualstudio and coverlet, plus the two integration-host packages below.
  • Data access is not mocked at all — a real Postgres container. In-memory and SQLite providers give
    false confidence about Npgsql mapping, and MatchQueries.ListAsync already depends on knowing
    exactly what does and does not translate to SQL.
  • Doubles are allowed only at genuinely external or non-deterministic edges, and are hand-written
    fakes in the test project, a few lines each:
    • the OIDC/Keycloak handshake → a test AuthenticationHandler registered in the factory;
    • time → TimeProvider, with the framework's FakeTimeProvider if a clock is ever injected;
    • any future outbound HTTP → a stub HttpMessageHandler.
  • If some later change genuinely needs a substitute library, that is a deliberate amendment to this
    issue, not a quiet package addition.

Tasks

  • Add Testcontainers.PostgreSql and Microsoft.AspNetCore.Mvc.Testing to the Testing
    ItemGroup of Directory.Packages.props (central package management: no inline Version=)
  • Create tests/Ssabba.Infrastructure.Tests with a shared Postgres fixture that applies the
    migrations once per run, and register it in Ssabba.slnx
  • Create tests/Ssabba.Web.Tests with a WebApplicationFactory and the test authentication
    handler, reusing the same fixture
  • Mark the container-backed tests with a trait so dotnet test --filter still runs the domain
    tier for contributors without Docker
  • Run the tiers in .github/workflows/ci.yml
  • Record how to run each tier in CLAUDE.md, and in CONTRIBUTING.md when Contributor guide (CONTRIBUTING.md) #29 lands

Umbrella for #34 and #30.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: ciGitHub Actions workflowsarea: dataEF Core, DbContext and migrations (Ssabba.Infrastructure)area: domainEntities and rating maths (Ssabba.Domain)area: webBlazor host and API endpoints (Ssabba.Web)type: choreMaintenance, refactors, tooling

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions