๐งช Integration Testing Tiers
InventoryAlert uses a Three-Tier architecture within the InventoryAlert.IntegrationTests project to balance testing speed with system realism.
๐๏ธ Technical Foundationโ
All tiers share a unified infrastructure:
TestFixture: Manages the lifecycle of Postgres, WireMock, and the Docker Log Reader.SetupDI.cs: Reuses production code (Composition Root) to build the test dependency graph.Respawn: Automatically truncates the database between every test run.Sequential Execution: Enforced via[Collection("IntegrationTests")]to prevent data collisions.
๐ฅ Tier 1: White-box Handler Testsโ
Goal: Verify complex business logic using the real database but mocked external services.
- How it works: Resolves concrete services (e.g.,
PortfolioService) or SQS handlers (e.g.,MarketPriceAlertHandler) directly from the testIServiceProvider. - Validation:
- Direct database assertions using
IUnitOfWork. - In-memory log assertions using
TestLoggerProvider(avoids container scraping).
- Direct database assertions using
- Tooling: Production DI graph + Moq for third-party mocks.
- Best For: Price math, rule evaluation logic, and trade ledger updates.
๐ฅ Tier 2: Log-Aware API Testsโ
Goal: Verify the HTTP surface, middleware, and request-response lifecycle.
- How it works: Sends real HTTP requests to the running
inventory-apicontainer viaRestClient. - Validation:
- HTTP Status Codes and JSON payloads.
- Log Correlation: Scrapes container logs for the specific
X-Correlation-Idreturned in the response. Proves that internal "invisible" side-effects occurred.
- Tooling:
RestSharp+DockerLogReader. - Best For: Authentication, route parameters, and status code correctness.
๐ฅ Tier 3: Whole-Flow Orchestrationโ
Goal: Prove absolute application quality by verifying cross-project orchestration.
- How it works: Initiates an action via the API and waits for a side-effect in a different part of the system after background processing.
- Scenario Example:
POST /api/v1/events(via API).- Event travels through SQS.
- Worker consumes event and processes business logic.
- Worker updates the database.
- Test polls
GET /api/v1/notifications(via API) to confirm the user sees the result.
- Tooling:
WaitHelperfor polling +WireMockAdmin API for seeding external quotes. - Best For: Proving that the API and Worker projects are correctly integrated via the event bus.
๐ ๏ธ Developer Patternsโ
1. Mocking External Services (WireMock)โ
Use the WireMock instance in the fixture to define behavior for Finnhub:
Fixture.WireMock
.Given(Request.Create().WithPath("/quote").WithParam("symbol", "AAPL"))
.RespondWith(Response.Create().WithStatusCode(200).WithBody("{\"c\": 150}"));
2. Asserting Internal Logs (Tier 1)โ
AssertLog("Dispatched real-time notification");
3. Waiting for Async Results (Tier 3)โ
await WaitHelper.WaitForConditionAsync(async () => {
var res = await Client.GetAsync("/api/v1/notifications");
return res.Content.Contains("AAPL Alert");
}, timeoutSeconds: 30);