Course contentsShow
← C#
Lesson 1686 of 1,90815. Software Quality and TestingFree lesson

Audit Log Verification

Assert that system changes are correctly logged with expected metadata.

Audit Log Verification

In this lesson, you will learn how to design automated tests that verify whether critical system state changes correctly trigger the generation of immutable, metadata-rich audit logs.

The Importance of Audit Integrity

In enterprise systems, an audit log isn't just a debugging tool; it is a compliance requirement. When a business-critical action occurs—such as a user permission change or a financial transaction—the system must capture who did what, when they did it, and what the previous and current state looked like.

Testing this manually is error-prone. Instead, we use integration tests to assert that the audit trail is physically persisted to the underlying store (e.g., a SQL database or a specialized audit service) exactly as expected.

Implementation Strategy

To verify audit logs, your test should follow the Arrange-Act-Assert pattern, with a specific focus on the persistence side effect.

[Fact]
public async Task UpdateUserRole_ShouldCreateAuditLog_WithCorrectMetadata()
{
    // Arrange: Setup a user and the system under test
    var userId = Guid.NewGuid();
    var auditor = "AdminUser_01";
    
    // Act: Perform the action that triggers an audit
    await _userService.UpdateRoleAsync(userId, "Manager", auditor);

    // Assert: Fetch the log entry and verify metadata
    var auditEntry = await _auditRepository.GetLatestEntryAsync(userId);
    
    Assert.NotNull(auditEntry);
    Assert.Equal("RoleUpdate", auditEntry.ActionType);
    Assert.Equal(auditor, auditEntry.ActorId);
    Assert.Contains("Manager", auditEntry.Payload);
    Assert.True(auditEntry.Timestamp > DateTime.UtcNow.AddSeconds(-5));
}

Avoiding False Positives

When verifying logs, avoid mocking the audit writer itself. If you mock the logger, you are testing your test configuration rather than the system's integration. Instead, use your Shared Test Infrastructure Abstractions to query the actual destination—whether that is a database, a file, or an event log—to ensure that the data serialization and persistence logic are functioning end-to-end. If your system relies on Eventual Consistency, ensure your verification logic accounts for potential transmission delays using a polling mechanism rather than an immediate assertion.

Key Takeaway: Audit log verification ensures that every high-stakes operation leaves a verifiable, immutable footprint containing complete contextual metadata within your persistent storage.