-
Notifications
You must be signed in to change notification settings - Fork 1
Event Annotations
Requests can be marked with RequestResponseMetaType.Event to give them special styling in diagrams. Event-annotated notes are rendered with:
- A light blue background (
#cfecf7) - Smaller font size (11px)
- Rounded corners
This is useful for distinguishing genuinely asynchronous or non-HTTP interactions — such as Kafka events, EventGrid notifications, RabbitMQ messages, SNS/SQS, or webhooks — from standard HTTP request/response flows.
⚠️ Important: Do NOT useMessageTrackerfor HTTP-based dependencies. If the real production interaction between your SUT and a dependency is HTTP, you must route it throughTestTrackingMessageHandlerinstead. UsingMessageTrackerfor HTTP calls produces event-style diagram arrows (blue notes, no HTTP method, no status code, no headers) that are misleading and inconsistent with the rest of the diagram. See Tracking Dependencies#faking-dependencies-getting-proper-http-tracking for the correct approaches to faking HTTP dependencies (WireMock, JustEat HttpClient Interception, in-memory fake APIs, etc.).
The MessageTracker class makes it easy to log non-HTTP interactions — such as events, messages, or commands sent via Kafka, EventGrid, RabbitMQ, SNS, or any other transport — so they appear in the generated sequence diagrams alongside regular HTTP traffic.
Register MessageTracker in your WebApplicationFactory startup, alongside your existing tracking setup:
builder.ConfigureTestServices(services =>
{
services.TrackDependenciesForDiagrams(new XUnitTestTrackingMessageHandlerOptions { ... });
services.TrackMessagesForDiagrams(callingServiceName: "My API");
});This registers MessageTracker as a singleton in DI, along with IHttpContextAccessor (needed to read test-tracking headers from the current request context).
Inject MessageTracker into any fake or stub that simulates publishing or sending messages. Call TrackMessageRequest when the message is sent, and TrackMessageResponse when the publish completes:
public class FakeEventPublisher : IEventPublisher
{
private readonly MessageTracker _tracker;
public FakeEventPublisher(MessageTracker tracker)
{
_tracker = tracker;
}
public Task PublishAsync(OrderCreatedEvent @event)
{
var correlationId = _tracker.TrackMessageRequest(
protocol: "Send (Event Protocol)",
destinationName: "Order Service",
destinationUri: new Uri("event://order-service/order_events"),
payload: @event);
_tracker.TrackMessageResponse(
protocol: "Send (Event Protocol)",
destinationName: "Order Service",
destinationUri: new Uri("event://order-service/order_events"),
requestResponseId: correlationId);
return Task.CompletedTask;
}
}| Parameter | Description |
|---|---|
protocol |
The transport label shown in the diagram (e.g. "Send (Event Protocol)", "Kafka", "SNS", "RabbitMQ"). |
destinationName |
The name of the destination service or topic shown in the diagram. |
destinationUri |
A URI representing the destination (e.g. new Uri("event://order-service/order_events")). The path portion appears in the diagram arrow label. |
payload |
The message payload — serialised to JSON and shown in the diagram note. |
requestResponseId |
The correlation ID returned by TrackMessageRequest, used to pair the request and response. |
responsePayload |
Optional response payload for TrackMessageResponse (e.g. an acknowledgement). |
If your payloads require specific serialisation settings, pass JsonSerializerOptions to the registration:
services.TrackMessagesForDiagrams(
callingServiceName: "My API",
serializerOptions: new JsonSerializerOptions { WriteIndented = true });This is one of the most common sources of confusion. The two mechanisms produce visually different outputs in your diagrams, and using the wrong one leads to misleading documentation.
HTTP tracking (via TestTrackingMessageHandler) produces:
caller -> scvApi: GET: /v2/identifiers?ssoId=sub
note left ← white background, standard note
[Accept=application/json]
end note
scvApi --> caller: 200 OK
note right ← white background, status code visible
[Content-Type=application/json]
{ "customerId": "custNbr123" }
end note
- Arrow label shows the HTTP method (
GET:,POST:, etc.) - Response shows the HTTP status code (
200 OK,404 Not Found, etc.) - Request and response headers are captured
- Request and response bodies are captured
- Notes have a white background (standard styling)
Event tracking (via MessageTracker) produces:
caller -> scvApi: HTTP: /v2/identifiers?ssoId=sub
note<<eventNote>> left ← BLUE background, rounded corners
"sub"
end note
scvApi --> caller: Responded ← no status code
- Arrow label shows the protocol string you passed (e.g.
"HTTP","Kafka","SNS") - Response always shows
"Responded"— no HTTP status code - No headers are captured
- Only the payload you explicitly pass appears in the note
- Notes have a light blue background with rounded corners (event styling)
| The real production interaction is... | Use | Why |
|---|---|---|
| HTTP (REST API, GraphQL over HTTP, gRPC-web) | TestTrackingMessageHandler |
Captures full HTTP semantics (method, status, headers, body) |
| Kafka event / message | MessageTracker |
No HTTP involved; protocol is Kafka |
| RabbitMQ / SNS / SQS message | MessageTracker |
No HTTP involved; protocol is the message broker |
| EventGrid / Azure Service Bus notification | MessageTracker |
Asynchronous messaging, not request/response HTTP |
| Webhook (your SUT sends an HTTP call to a callback URL) | TestTrackingMessageHandler |
It's still HTTP — track it properly through the pipeline |
| gRPC (over HTTP/2) | TestTrackingMessageHandler |
gRPC uses HTTP/2 transport — track the HTTP layer |
A common pattern that leads to incorrect diagrams is mocking a service client interface and then wrapping the mock to manually log calls via MessageTracker:
// ❌ WRONG — produces event-style (blue) arrows for what is actually an HTTP call
public class TrackingScvProvider : IScvProvider
{
private readonly IScvProvider _mock; // NSubstitute mock
private readonly MessageTracker _tracker;
public async Task<ScvResponse> GetIdentifiersAsync(string ssoId)
{
var id = _tracker.TrackMessageRequest(
protocol: "HTTP",
destinationName: "SCV API",
destinationUri: new Uri($"http://scv/v2/identifiers?ssoId={ssoId}"),
payload: ssoId);
var result = await _mock.GetIdentifiersAsync(ssoId);
_tracker.TrackMessageResponse(
protocol: "HTTP",
destinationName: "SCV API",
destinationUri: new Uri("http://scv/v2/identifiers"),
requestResponseId: id);
return result;
}
}The fix: Replace the mock with a real HTTP fake (WireMock, JustEat HttpClient Interception, or an in-memory API) and let TestTrackingMessageHandler capture the call automatically. See Tracking Dependencies#faking-dependencies-getting-proper-http-tracking for detailed examples of each approach.
Getting Started
Common Tasks
Integration Guides
- Integration xUnit3
- Integration xUnit2
- Integration NUnit
- Integration MSTest
- Integration TUnit
- Integration BDDfy xUnit3
- Integration LightBDD xUnit2
- Integration LightBDD xUnit3
- Integration LightBDD TUnit
- Integration ReqNRoll xUnit2
- Integration ReqNRoll xUnit3
- Integration ReqNRoll TUnit
Extensions
- Integration AtlasDataApi Extension
- Integration BigQuery Extension
- Integration Bigtable Extension
- Integration BlobStorage Extension
- Integration ClickHouse Extension
- Integration CloudStorage Extension
- Integration CosmosDB Extension
- Integration Dapper Extension
- Integration DynamoDB Extension
- Integration EF Core Relational Extension
- Integration Elasticsearch Extension
- Integration EventBridge Extension
- Integration EventHubs Extension
- Integration Grpc Extension
- Integration Kafka Extension
- Integration MassTransit Extension
- Integration MongoDB Extension
- Integration MySqlConnector Extension
- Integration Npgsql Extension
- Integration Oracle Extension
- Integration PubSub Extension
- Integration Redis Extension
- Integration S3 Extension
- Integration ServiceBus Extension
- Integration SNS Extension
- Integration Spanner Extension
- Integration SqlClient Extension
- Integration Sqlite Extension
- Integration SQS Extension
- Integration StorageQueues Extension
- Integration OpenTelemetry Extension
- Integration DispatchProxy Extension
- Integration MediatR Extension
- Integration PlantUML IKVM
Configuration
- Tracking Dependencies
- Tracking Custom Dependencies
- HTTP Tracking Setup
- Report Configuration
- Diagram Customisation
- Phase-Aware Tracking
- Content Formatting
- PlantUML Server Configuration
Features
- Generated Reports
- Search Syntax
- Component Diagrams
- PlantUML Browser Rendering
- Inline SVG Rendering
- Internal Flow Tracking
- Tags and Attributes
- Excluding Requests
- Excluded Headers
- Multi-Host Test Architectures
- Event-Driven Architecture Testing
- Service Bus Tracking Patterns
- Background Thread Correlation
- Parallel-Safe Background Correlation
- Event & Message Tracking
- Assertion Tracking
- Step Tracking
- Tabular Attributes
- Large Response and Diagram Handling
- Diagnostics and Debugging
- CI Summary Integration
- CI Artifact Upload
- Merging Parallel Reports
Reference