-
Notifications
You must be signed in to change notification settings - Fork 1
Integration BDDfy xUnit3
Example project: A complete working example is available at
Example.Api/tests/Example.Api.Tests.Component.BDDfy.xUnit3/.
This guide walks you through integrating TestTrackingDiagrams with BDDfy using xUnit v3 as the test runner. After completing this guide, your BDDfy tests will automatically generate:
- PlantUML sequence diagrams from HTTP traffic between your service and its dependencies
- HTML reports with embedded diagrams and BDD steps (Given/When/Then/And/But)
- YAML specification files with step information included
- Enhanced BDDfy native HTML report with sequence diagrams injected alongside each scenario
- .NET 10.0 SDK or later
- An ASP.NET Core API project to test (your "Service Under Test")
- Basic familiarity with BDDfy's fluent API or convention-based step patterns
Create a new xUnit test project:
dotnet new xunit -n MyApi.Tests.Component.BDDfyImportant: xUnit v3 runs tests out-of-process, so you must set <OutputType>Exe</OutputType> in your .csproj:
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<OutputType>Exe</OutputType>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>Add the following packages to your test project:
dotnet add package TestTrackingDiagrams.BDDfy.xUnit3
dotnet add package TestStack.BDDfy --version 8.0.1.3
dotnet add package xunit.v3 --version 2.0.2
dotnet add package xunit.runner.visualstudio --version 3.0.2
dotnet add package Microsoft.AspNetCore.Mvc.Testing
dotnet add package Microsoft.NET.Test.SdkYour <ItemGroup> should look like this:
<ItemGroup>
<PackageReference Include="TestTrackingDiagrams.BDDfy.xUnit3" Version="1.23.8" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.12" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="TestStack.BDDfy" Version="8.0.1.3" />
<PackageReference Include="xunit.v3" Version="2.0.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>Create an Infrastructure/BDDfyTestSetup.cs file. This class uses xUnit v3's [assembly: AssemblyFixture] to set up and tear down the test environment. It:
- Configures BDDfy's diagram-capturing processor
- Creates a
WebApplicationFactoryfor your API with HTTP tracking - Generates all reports after tests complete
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.AspNetCore.TestHost;
using TestTrackingDiagrams;
using TestTrackingDiagrams.BDDfy.xUnit3;
using Xunit;
[assembly: AssemblyFixture(typeof(MyApi.Tests.Component.BDDfy.Infrastructure.BDDfyTestSetup))]
namespace MyApi.Tests.Component.BDDfy.Infrastructure;
public class BDDfyTestSetup : IAsyncLifetime
{
private const string ServiceUnderTestName = "My API";
private static WebApplicationFactory<Program>? _factory;
public static WebApplicationFactory<Program> Factory => _factory!;
public ValueTask InitializeAsync()
{
// Register BDDfy diagram processors (must be called before any BDDfy tests run)
BDDfyDiagramsConfigurator.Configure();
BDDfyScenarioCollector.StartRunTime = DateTime.UtcNow;
_factory = new WebApplicationFactory<Program>().WithWebHostBuilder(builder =>
{
builder.ConfigureTestServices(services =>
{
services.TrackDependenciesForDiagrams(new BDDfyTestTrackingMessageHandlerOptions
{
CallingServiceName = ServiceUnderTestName,
PortsToServiceNames =
{
{ 80, ServiceUnderTestName },
{ 5001, "Downstream Service A" },
{ 5002, "Downstream Service B" }
}
});
});
});
return ValueTask.CompletedTask;
}
public ValueTask DisposeAsync()
{
BDDfyScenarioCollector.EndRunTime = DateTime.UtcNow;
// Generate HTML and YAML reports with diagrams
BDDfyReportGenerator.CreateStandardReportsWithDiagrams(
new ReportConfigurationOptions
{
SpecificationsTitle = "My API Specifications"
});
_factory?.Dispose();
return ValueTask.CompletedTask;
}
public static HttpClient CreateTrackingClient()
{
return _factory!.CreateTestTrackingClient(
new BDDfyTestTrackingMessageHandlerOptions
{
FixedNameForReceivingService = ServiceUnderTestName
});
}
}| Component | Purpose |
|---|---|
BDDfyDiagramsConfigurator.Configure() |
Registers BDDfy processors that capture scenario info and enhance BDDfy's HTML report |
BDDfyScenarioCollector.StartRunTime |
Sets the test run start time for the report header |
TrackDependenciesForDiagrams() |
Configures HTTP tracking for outgoing requests from the SUT |
CreateTestTrackingClient() |
Creates an HttpClient that tracks all requests for diagram generation |
BDDfyReportGenerator.CreateStandardReportsWithDiagrams() |
Generates all report files in bin/Debug/net10.0/Reports/
|
Create an Infrastructure/BaseFixture.cs that provides each test with a tracking-enabled HttpClient:
namespace MyApi.Tests.Component.BDDfy.Infrastructure;
public abstract class BaseFixture : IDisposable
{
protected HttpClient Client { get; }
protected BaseFixture()
{
Client = BDDfyTestSetup.CreateTrackingClient();
}
public void Dispose() => Client.Dispose();
}Create a test class that uses BDDfy's fluent API. Each test method calls this.BDDfy() which:
- Executes your Given/When/Then steps
- Captures the scenario info (title, steps, result) for report generation
- Captures the scenario ID for BDDfy HTML report enhancement
using System.Net;
using System.Net.Http.Json;
using MyApi.Tests.Component.BDDfy.Infrastructure;
using TestStack.BDDfy;
using Xunit;
[Story(
AsA = "dessert provider",
IWant = "to create cakes from ingredients",
SoThat = "customers can enjoy delicious cakes")]
public class CakeFeature : BaseFixture
{
private HttpResponseMessage? _response;
[Fact]
public void Calling_Create_Cake_Endpoint_Returns_Cake()
{
this.Given(x => x.GivenAValidPostRequest())
.When(x => x.WhenTheRequestIsSent())
.Then(x => x.ThenTheResponseShouldBeSuccessful())
.WithTags("happy-path", "endpoint:/cake")
.BDDfy();
}
[Fact]
public void Calling_Create_Cake_Endpoint_Without_Eggs_Returns_Bad_Request()
{
this.Given(x => x.GivenAValidPostRequest())
.And(x => x.AndTheRequestBodyIsMissingEggs())
.When(x => x.WhenTheRequestIsSent())
.Then(x => x.ThenTheResponseShouldBeBadRequest())
.WithTags("endpoint:/cake")
.BDDfy();
}
// Step methods
private async Task GivenAValidPostRequest() { /* ... */ }
private void AndTheRequestBodyIsMissingEggs() { /* ... */ }
private async Task WhenTheRequestIsSent() { /* ... */ }
private async Task ThenTheResponseShouldBeSuccessful() { /* ... */ }
private void ThenTheResponseShouldBeBadRequest() { /* ... */ }
}| Tag | Purpose |
|---|---|
endpoint:/cake |
Sets the endpoint label on the feature in the report |
happy-path |
Marks the scenario as a "happy path" (highlighted in reports, filterable) |
BDDfy captures step names from your method names. The first word is used as the keyword (Given/When/Then/And/But):
| Method Name | Rendered Step |
|---|---|
GivenAValidPostRequest |
Given a valid post request |
WhenTheRequestIsSent |
When the request is sent |
ThenTheResponseShouldBeSuccessful |
Then the response should be successful |
AndTheRequestBodyIsMissingEggs |
And the request body is missing eggs |
BDDfy's [Story] attribute provides feature-level metadata that appears in the reports:
[Story(
AsA = "dessert provider",
IWant = "to create cakes from ingredients",
SoThat = "customers can enjoy delicious cakes")]
public class CakeFeature : BaseFixtureThe AsA/IWant/SoThat narrative appears as a feature description in the generated reports. The class name (converted from CamelCase to Camel case) becomes the feature display name.
dotnet testAfter a successful run, check the output directory (bin/Debug/net10.0/) for generated reports:
| File | Location | Description |
|---|---|---|
ComponentSpecifications.yml |
Reports/ |
YAML specifications with BDDfy steps |
ComponentSpecificationsWithExamples.html |
Reports/ |
HTML specifications with embedded diagrams |
FeaturesReport.html |
Reports/ |
Test run report with diagrams and execution summary |
BDDfy.html |
Root output dir | BDDfy's native HTML report, enhanced with sequence diagrams |
The library automatically enhances BDDfy's native HTML report by injecting sequence diagram images after each scenario's steps. This happens via a custom IBatchProcessor that runs after BDDfy generates its report. No additional configuration is needed — it works automatically when you call BDDfyDiagramsConfigurator.Configure().
The integration uses three coordinated components:
-
BDDfyTestTrackingMessageHandlerOptions— Provides the test tracking ID from xUnit v3'sTestContext.Current.Test.UniqueIDso that HTTP requests are tagged with the correct test ID during execution. -
DiagramCapturingProcessor— A BDDfyIProcessorthat runs during eachthis.BDDfy()call. It captures the scenario title, steps (Given/When/Then), tags, result, and maps them to the xUnit test ID. -
DiagramEnhancingBatchProcessor— A BDDfyIBatchProcessorthat runs after all tests complete. It reads BDDfy's native HTML report and injects sequence diagram images next to each scenario. -
BDDfyReportGenerator— Called in the assembly fixture'sDisposeAsync, generates the three standard TestTrackingDiagrams reports with BDDfy step data and diagrams.
If you forget to call Configure(), the DiagramCapturingProcessor won't be registered and no scenario data will be captured. Use xUnit v3's [assembly: AssemblyFixture] to ensure it runs first.
Without this, xUnit v3 tests won't execute because the out-of-process runner requires an executable entry point.
BDDfy supports async step methods that return Task. The fluent API accepts Func<TScenario, Task> lambdas. Your HTTP call steps can be async.
BDDfy converts your class name to a readable title. CakeFeature becomes "Cake feature". Use the [Story(Title = "...")] attribute to customize.
The BDDfy HTML report enhancement requires BDDfyDiagramsConfigurator.Configure() to register the batch processor. The enhancement only works when BDDfy generates its HTML report (the default behaviour).
Customize report generation in the BDDfyReportGenerator.CreateStandardReportsWithDiagrams() call:
BDDfyReportGenerator.CreateStandardReportsWithDiagrams(
new ReportConfigurationOptions
{
SpecificationsTitle = "My Custom Title",
HtmlSpecificationsFileName = "CustomSpecs",
HtmlTestRunReportFileName = "CustomReport",
YamlSpecificationsFileName = "CustomYaml",
PlantUmlServerBaseUrl = "https://my-plantuml-server.com/plantuml",
ExcludedHeaders = new[] { "Authorization", "X-Api-Key" },
SeparateSetup = true,
HighlightSetup = true
});Insert custom PlantUML content into diagrams:
using TestTrackingDiagrams.BDDfy.xUnit3;
TrackingDiagramOverride.InsertPlantUml("note right: Custom annotation");
TrackingDiagramOverride.InsertTestDelimiter("Phase 1");
// Override the start/end of diagram generation
TrackingDiagramOverride.StartOverride();
TrackingDiagramOverride.EndOverride();
// Explicitly mark the boundary between setup and action phases
TrackingDiagramOverride.StartAction();BDDfy supports automatic setup separation. When SeparateSetup = true is set on ReportConfigurationOptions, HTTP calls made during GIVEN steps are automatically wrapped in a visual "Setup" partition in the diagram. The boundary is detected implicitly when the test transitions from a GIVEN step to a WHEN or THEN step — no manual StartAction() call is needed.
This works via a custom IStepExecutor that tracks the current BDD step type during execution. It is registered automatically when you call BDDfyDiagramsConfigurator.Configure().
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