In this lesson, you will learn how to write integration tests that verify whether your API requests correctly transform the underlying database state.
The Objective of Consistency Testing
When building a Web API, your endpoints often trigger complex workflows—updating related tables, calculating fields, or firing events. A unit test might verify that your service logic returns the correct value, but it won’t tell you if the database actually reflects that state correctly. To test for consistency, we need an Integration Test that follows the "Arrange-Act-Assert" pattern, focusing on the state of the database after the API call.
A Concrete Example
Imagine an endpoint that updates a user's subscription status. Consistency testing ensures that after calling the PUT endpoint, the Subscriptions table and the AuditLogs table are perfectly in sync.
Using WebApplicationFactory, we can spin up an in-memory database or a containerized test database to verify this:
[Fact]
public async Task UpgradeSubscription_UpdatesUserAndLogsEntry()
{
// 1. Arrange: Setup initial state
var client = _factory.CreateClient();
var userId = Guid.NewGuid();
await SeedUserAsync(userId, "Basic");
// 2. Act: Execute the API call
var response = await client.PutAsync($"/api/users/{userId}/upgrade", null);
response.EnsureSuccessStatusCode();
// 3. Assert: Verify consistency in the database
using var scope = _factory.Services.CreateScope();
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
var user = await context.Users.FindAsync(userId);
var log = await context.AuditLogs.FirstOrDefaultAsync(l => l.UserId == userId);
Assert.Equal("Premium", user.SubscriptionLevel); // Verify state
Assert.NotNull(log); // Verify side-effect consistency
Assert.Equal("UpgradeAction", log.ActionType);
}
Why This Matters
If your business logic involves a Transactional Unit of Work, consistency testing is your safety net. Without it, you might accidentally introduce bugs where the main entity updates, but the related audit trail fails to write, leading to data corruption that is difficult to debug in production. By querying the database directly after the request completes, you guarantee that your API isn't just returning a 200 OK, but is actually performing the atomic operations your system requires.
Key Takeaway: Testing data consistency requires querying the database directly after an API request to ensure that all side effects, state changes, and related records are correctly persisted.