Testing
Overview
Tests live in tests/SalonCloud.Tests/ and use xUnit with Testcontainers (real PostgreSQL 16 containers) and WebApplicationFactory (in-memory ASP.NET Core hosts).
Prerequisites
- Docker (Testcontainers pulls Postgres 16)
- .NET 10 SDK
Running tests
Test structure
The test project references all service projects. Web projects are aliased to avoid name collisions (e.g., AccountsWeb, BookingWeb).
Integration test infrastructure
PostgresFixture
PostgresFixture.cs implements IAsyncLifetime and manages a single Testcontainers Postgres 16 instance shared across all integration tests:
max_connections=1000— needed because ~300+WebApplicationFactoryinstances accumulateMinPoolSize=1to keep peak idle connections manageable- Runs EF migrations for all service DbContexts before any test runs
- Sets up Observability TCP stub so Accounts onboard tests don't burn retry budget
- Sets
Otp__MaxIssuesPerWindow=10000to prevent throttle exhaustion - Disables
HealthSnapshotandRuleEngineby default
Collection fixture pattern
Integration tests use xUnit collection fixtures:
Key pattern: each test creates a fresh WebApplicationFactory (fresh DI container, fresh in-memory host), but all share the same Postgres container via the collection fixture.
What's tested (integration)
- Sync batch: happy path, NUL-byte rejection, duplicate batch idempotency, suppression detection, clock-skew clamping, lease conflicts, unauthorized/forbidden, sequentia restore
- Booking: availability, holds, OTP flow, booking create/cancel/reschedule, reconciliation, outbox pull/ack, rate limiting
- Auth: login/logout, OTP verify, session refresh, token validation
- Onboarding: self-onboard, store activation/deactivation
- Device registration: device bind, device revoke
- Operator admin: role CRUD, operator CRUD, permission management, audit log
- Entitlement management: per-store override, feature catalog
- Notification dispatch: booking confirmations, reminders
- SMS webhooks: inbound/status callbacks (Twilio)
- DataHub: RLS enforcement, PII hardening, view correctness, schema migrations
- Capability convergence: poller applies all pages, cursor advances correctly
- Media: image upload validation, S3 put
- CDK synth: VPC structure, RDS properties, WAF rules, ALB path routing, Service Connect wiring
Unit tests
Pure unit tests (no database, no DI container) cover:
CDK synth tests
tests/SalonCloud.Tests/Infra/CdkSynthTests.cs — synthesizes CloudFormation templates and asserts on:
- VPC: 2 AZs, subnets, NAT gateway count
- RDS: engine version, instance class, deletion protection
- WAF: rule presence
- ALB: path-based routing rules,
/internal/*blocking - Service Connect: namespace, service entries
Test frameworks and dependencies
When adding new tests
- Integration: Use
[Collection("postgres")]to share the Postgres container. Create a freshWebApplicationFactoryper test. UsePostgresFixturehelper methods to seed prerequisite state. - Unit: No DB, no DI. Test pure functions in isolation. Follow the existing pattern of class-per-test-subject.
- CDK: Add to
CdkSynthTests.csif testing infrastructure shape, or create new test class for new stack assertions.
Remember: DataHub is a migration-only project with no web host — its tests verify SQL views and RLS via direct database queries from integration tests.
More on the architecture these tests exercise in Architecture and Data Flow.