-
Notifications
You must be signed in to change notification settings - Fork 1
Testing Strategy
TrackHub tests in three layers, each with a different cost and a different guarantee. Knowing which layer catches which class of bug is the point — several production defects have shipped past a fully green suite because they belonged to a layer that was not running.
Related pages: Inter-Service Communication · Coding Standards
| Layer | Location | Guarantees | Needs |
|---|---|---|---|
| Unit tests | Each repository's tests/
|
Handler and reader logic (EF InMemory + Moq) | Nothing |
| Contract tests |
TrackHub.IntegrationTests/ (its own solution) |
Every inter-service GraphQL call validates against the producer's real schema, and critical flows round-trip through real resolvers | Sibling repository checkouts only — no database, no running services |
| Smoke tests |
tests/TrackHub.SmokeTests (local only, not published) |
The deployed stack works: health, tokens, authorization, real database | A running local IIS deployment |
# Contract tests — run after ANY change to a GraphQL surface or inter-service client
dotnet test TrackHub.IntegrationTests/TrackHub.IntegrationTests.slnxThey run in seconds, and a failure names the exact broken call.
The suite covers these consumer → producer pairs:
Router → Manager · Router → Telemetry · Router → Geofence · Router → TripManagement · Reporting → Manager · Reporting → Telemetry · Reporting → Router · Reporting → Geofence · Reporting → TripManagement · Manager → Security · Manager → Router · Security → Manager · Geofencing → Manager · TripManagement → Manager · TripManagement → Telemetry
Every GraphQL query string a consumer ships — the exact internal const production sends, exposed via [assembly: InternalsVisibleTo] — is validated against the producer's real, in-process-built schema. A renamed or removed field, argument or input property fails the matching test with a message naming the call.
For critical and complex flows, the consumer's real reader or writer executes against the producer's real resolvers over an in-process IGraphQLClient; only the mediator (ISender) behind the resolvers is faked.
This catches what Layer A cannot: serialization drift — enum, UUID and DateTime coercion, casing, and field-to-property mapping on both sides.
Enum values travel in GraphQL variables and are invisible to Layer A. Every enum-typed literal a client sends (
checkType,triggerType,result, …) must have a Layer B case asserting it coerces into the producer's enum. This is the single most common gap.
| Project | Purpose |
|---|---|
src/TrackHub.ServiceContracts.Harness |
Test-support library: InProcessGraphQLClient (an IGraphQLClient over a producer IRequestExecutor), the client factory, and the producer schema/executor builder that reuses the production AddTrackHubGraphQLServer configuration |
tests/TrackHub.ServiceContracts.Tests |
Contract and round-trip tests for every producer/consumer pair |
The projects reference service source by relative path, so all TrackHub repositories must be cloned side by side.
The suite also exports each producer's SDL to TrackHub/schemas/<service>.graphql (the SchemaSdlExport test), which is what the portal's npm run codegen validates every frontend operation against. See Frontend.
Unit tests run against EF InMemory, which is fast and convenient — and diverges from PostgreSQL in ways that have shipped bugs:
| Divergence | Consequence |
|---|---|
InMemory defaults to TrackAll; Manager's ApplicationDbContext is NoTracking
|
A row fetched for mutation without Attach is silently discarded at SaveChangesAsync. The unit test passes. |
InMemory has no json column semantics |
Distinct() / GroupBy() over an entity containing transporter_position.attributes fails on real PostgreSQL with 42883. The unit test passes. |
| InMemory evaluates un-translatable LINQ client-side |
OrderBy over a projected record struct member, or GroupBy(...).Select(g => g.First()), throws only against Npgsql. The unit test passes. |
Infrastructure.UnitTests/WorkforceQueryTranslationTests demonstrates the pattern: run the reader against the real Npgsql provider pointed at an unreachable host. Translation happens before the connection is attempted, so a translation failure is distinguishable from a connection failure — and no database is required.
Use this whenever a query's translatability is in question.
Handler unit tests do not run the pipeline. They call the handler directly, so none of the behaviors execute:
-
[Authorize]is not enforced -
AccountScopeBehaviordoes not run — tenant isolation is untested -
[Caching]and[RateLimiting]are inert - validators do not run
The behavior tests in Common.Application.Tests/Behaviors/AccountScopeBehaviorTests are the only proof that tenant scoping works. The per-service AccountScopeCoverageTests gate proves every request type is classified, but not that the classification is correct.
-
Never re-type a GraphQL query string in a test. Reference the production
internal const, or the test validates a copy that has already drifted. - Mutation-test every guard. A green suite is not evidence a guard works — twice, an audit has found a HIGH-severity bug behind a fully green suite because a test asserted the buggy behaviour. Break the guard deliberately and confirm the test goes red.
- Every new inter-service call gets a Layer A test, and complex or critical ones get a Layer B round-trip.
- Provider mappers carry a value-correctness unit test. The provider fetch and mapping is the money path — speed, odometer and position feed reports, and billing.
-
Assert round-trip properties, not literals, for anything timezone-dependent. A
datetime-localhelper that skips the offset shift round-trips correctly underTZ=UTC, which is exactly what dev boxes and CI run.
| Scope | Command |
|---|---|
| A backend repository |
dotnet build && dotnet test for its solution |
| Any GraphQL surface change | dotnet test TrackHub.IntegrationTests/TrackHub.IntegrationTests.slnx |
| The portal | npm run typecheck && npm test && npm run build |
| Help content |
npm run help:check (also runs on predev / prebuild) |
| A deployed environment |
tests/TrackHub.SmokeTests against the running stack |
Platform
- Architecture
- Technology
- Inter-Service Communication
- Database
- Security and Identity
- User Permissions Overview
Services
- Manager
- Telemetry
- Router
- Adding a Provider
- Geofencing
- Trip Management
- Reporting
- Common Library
- Frontend
Engineering
User docs
- User Guide (ships in the app)