-
Notifications
You must be signed in to change notification settings - Fork 1
Integration LightBDD xUnit3
Example project: A complete working example is available at
Example.Api/tests/Example.Api.Tests.Component.LightBDD.xUnit3/. You can reference it alongside this guide for a fully working implementation.
This guide walks you through integrating TestTrackingDiagrams with LightBDD using xUnit v3 as the test runner. After completing this guide, your LightBDD tests will automatically generate:
- PlantUML sequence diagrams from HTTP traffic between your service and its dependencies
- HTML reports with embedded diagrams (integrated into LightBDD's report pipeline)
- YAML specification files
LightBDD is a BDD framework that lets you write scenarios as C# method calls (given => ..., when => ..., then => ...) using its Runner.RunScenarioAsync pattern, with support for composite steps, tabular data, and rich reporting.
Migrating from LightBDD + xUnit 2? See Differences from xUnit 2 at the bottom of this guide.
- .NET 8.0 SDK or later
- An ASP.NET Core API project to test (your "Service Under Test")
- Basic familiarity with LightBDD
Create a new xUnit v3 test project:
dotnet new xunit -n MyApi.Tests.Component.LightBDDImportant: xUnit v3 test assemblies are standalone executables. Add
<OutputType>Exe</OutputType>to your.csproj:
<PropertyGroup>
<OutputType>Exe</OutputType>
</PropertyGroup>dotnet add package TestTrackingDiagrams.LightBDD.xUnit3
dotnet add package LightBDD.XUnit3
dotnet add package Microsoft.AspNetCore.Mvc.Testing
dotnet add package Microsoft.NET.Test.Sdk
dotnet add package xunit.v3
dotnet add package xunit.runner.visualstudioYour <ItemGroup> should look like this:
<ItemGroup>
<PackageReference Include="TestTrackingDiagrams.LightBDD.xUnit3" Version="1.24.10" />
<PackageReference Include="LightBDD.XUnit3" Version="3.12.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.5" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
<PackageReference Include="xunit.v3" Version="3.2.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>LightBDD for xUnit v3 uses a TestPipelineStartup to configure the test run. Create Infrastructure/ConfiguredLightBddScope.cs:
using System.Reflection;
using LightBDD.Core.Configuration;
using LightBDD.Framework.Configuration;
using LightBDD.XUnit3;
using TestTrackingDiagrams;
using TestTrackingDiagrams.LightBDD.xUnit3;
using Xunit.v3;
[assembly: TestPipelineStartup(typeof(ConfiguredLightBddScope))]
namespace MyApi.Tests.Component.LightBDD.Infrastructure;
public class ConfiguredLightBddScope : LightBddScope
{
protected override void OnConfigure(LightBddConfiguration configuration)
{
var testAssembly = Assembly.GetAssembly(typeof(ConfiguredLightBddScope))!;
// Wire up TestTrackingDiagrams report generation into LightBDD's report pipeline
configuration.ReportWritersConfiguration().CreateStandardReportsWithDiagrams(
testAssembly,
new ReportConfigurationOptions
{
SpecificationsTitle = "My API Specifications"
});
// Optional: Register global setup/teardown for HTTP fakes
configuration.ExecutionExtensionsConfiguration()
.RegisterGlobalTearDown("dispose factory", BaseFixture.DisposeFactory)
.RegisterGlobalSetUp("http fakes", StartHttpFakes, DisposeHttpFakes);
}
private void StartHttpFakes() { /* start your HTTP fakes here */ }
private void DisposeHttpFakes() { /* dispose your HTTP fakes here */ }
}Key points:
-
[assembly: TestPipelineStartup(typeof(ConfiguredLightBddScope))]is required — it tells xUnit v3 to use LightBDD's test pipeline. - The scope class extends
LightBddScope(a class, not an attribute like xUnit v2'sLightBddScopeAttribute). -
CreateStandardReportsWithDiagramshooks into LightBDD's native report pipeline, so reports are generated automatically when the test run ends.
Create Infrastructure/BaseFixture.cs. All your test classes will inherit from this:
using LightBDD.XUnit3;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.AspNetCore.TestHost;
using TestTrackingDiagrams.LightBDD.xUnit3;
namespace MyApi.Tests.Component.LightBDD.Infrastructure;
public abstract class BaseFixture : FeatureFixture, IDisposable
{
private static readonly WebApplicationFactory<Program>? SFactory;
protected HttpClient Client { get; }
private const string ServiceUnderTestName = "My API";
static BaseFixture()
{
SFactory = new WebApplicationFactory<Program>().WithWebHostBuilder(builder =>
{
builder.ConfigureTestServices(services =>
{
services.TrackDependenciesForDiagrams(new LightBddTestTrackingMessageHandlerOptions
{
CallingServiceName = ServiceUnderTestName,
PortsToServiceNames =
{
{ 80, ServiceUnderTestName },
{ 5001, "Downstream Service A" }
}
});
});
});
}
protected BaseFixture()
{
Client = SFactory!.CreateTestTrackingClient(
new LightBddTestTrackingMessageHandlerOptions
{
FixedNameForReceivingService = ServiceUnderTestName
});
}
public void Dispose() => Client.Dispose();
public static void DisposeFactory() => SFactory?.Dispose();
}Key points:
- The static constructor creates the
WebApplicationFactoryonce for all tests. - Each test instance gets its own
HttpClientvia the instance constructor. - The test inherits from
FeatureFixture(LightBDD's base class for xUnit v3). -
LightBddTestTrackingMessageHandlerOptionsautomatically resolves the current test context using LightBDD'sScenarioExecutionContext.
LightBDD uses partial classes — one file for the scenario definitions, one for the step implementations.
using LightBDD.Framework.Scenarios;
using LightBDD.XUnit3;
namespace MyApi.Tests.Component.LightBDD.Scenarios;
[FeatureDescription("/cake")]
public partial class Cake_Feature
{
[HappyPath]
[Scenario]
public async Task Calling_Create_Cake_Endpoint_Successfully()
{
await Runner.RunScenarioAsync(
given => A_valid_post_request_for_the_Cake_endpoint(),
when => The_request_is_sent_to_the_cake_post_endpoint(),
then => The_response_should_be_successful());
}
[Scenario]
public async Task Calling_Create_Cake_Endpoint_Without_Eggs()
{
await Runner.RunScenarioAsync(
given => A_valid_post_request_for_the_Cake_endpoint(),
but => The_request_body_is_missing_eggs(),
when => The_request_is_sent_to_the_cake_post_endpoint(),
then => The_response_http_status_should_be_bad_request());
}
}using System.Net;
using System.Net.Http.Json;
using MyApi.Tests.Component.LightBDD.Infrastructure;
namespace MyApi.Tests.Component.LightBDD.Scenarios;
public partial class Cake_Feature : BaseFixture
{
private HttpResponseMessage? _response;
private async Task A_valid_post_request_for_the_Cake_endpoint()
{
// Set up your request data using Client
}
private async Task The_request_body_is_missing_eggs()
{
// Modify request
}
private async Task The_request_is_sent_to_the_cake_post_endpoint()
{
_response = await Client.PostAsJsonAsync("cake", /* your request */);
}
private async Task The_response_should_be_successful()
{
_response!.StatusCode.Should().Be(HttpStatusCode.OK);
}
private async Task The_response_http_status_should_be_bad_request()
{
_response!.StatusCode.Should().Be(HttpStatusCode.BadRequest);
}
}Key points:
-
[FeatureDescription("/cake")]sets the endpoint label in the report (equivalent to@endpoint:/cakein Gherkin). -
[HappyPath]marks a scenario as a happy path (fromLightBDD.Contrib.ReportingEnhancements). - Steps are regular
async Taskmethods — method names are converted to readable text by LightBDD (underscores become spaces).
dotnet testOr, since xUnit v3 assemblies are standalone executables, you can run directly:
bin/Debug/net10.0/MyApi.Tests.Component.LightBDD.exeAfter the tests complete, check the bin/Debug/net10.0/Reports/ folder:
| File | Description |
|---|---|
ComponentSpecificationsWithExamples.html |
HTML specifications with embedded PlantUML sequence diagrams |
FeaturesReport.html |
HTML test run report with diagrams and execution summary |
ComponentSpecifications.yml |
YAML specifications |
LightBDD's adapter provides a TrackingDiagramOverride class for customising diagrams within a test:
using TestTrackingDiagrams.LightBDD.xUnit3;
// Insert a delimiter between multiple requests in the diagram
TrackingDiagramOverride.InsertTestDelimiter("Step 1");
// Insert raw PlantUML markup
TrackingDiagramOverride.InsertPlantUml("note over MyApi : Custom note");
// Override the start/end of diagram generation
TrackingDiagramOverride.StartOverride();
TrackingDiagramOverride.EndOverride();
// Explicitly mark the boundary between setup and action phases
TrackingDiagramOverride.StartAction();Setup separation: When
SeparateSetup = trueis set onReportConfigurationOptions, LightBDD automatically detects the boundary between GIVEN steps and WHEN/THEN steps. HTTP calls made during GIVEN steps are wrapped in a visual "Setup" partition in the diagram — no manualStartAction()call is needed.
Tip:
InsertTestDelimiteris particularly useful when using LightBDD's Tabular Parameters or TabularAttributes, where a single scenario runs multiple iterations. Insert a delimiter between each iteration to clearly separate them in the diagram.
Passed to CreateStandardReportsWithDiagrams:
| Property | Default | Description |
|---|---|---|
SpecificationsTitle |
"Specifications" |
Title shown at the top of reports |
PlantUmlServerBaseUrl |
"https://www.plantuml.com/plantuml" |
PlantUML server URL |
HtmlSpecificationsFileName |
"ComponentSpecificationsWithExamples" |
Output filename for specs HTML |
HtmlTestRunReportFileName |
"FeaturesReport" |
Output filename for test run HTML |
YamlSpecificationsFileName |
"ComponentSpecifications" |
Output filename for YAML specs |
HtmlSpecificationsCustomStyleSheet |
null |
Custom CSS appended to specs HTML |
ExcludedHeaders |
[] |
HTTP headers to exclude from diagrams |
SeparateSetup |
false |
When true, HTTP calls made during GIVEN steps are wrapped in a visual "Setup" partition in the diagram |
HighlightSetup |
true |
When true (and SeparateSetup is enabled), the setup partition is rendered with a background colour |
| Property | Description |
|---|---|
CallingServiceName |
Display name for the service making outgoing HTTP calls |
FixedNameForReceivingService |
Display name for the service receiving requests (your SUT) |
PortsToServiceNames |
Dictionary mapping port numbers to friendly service names. Unmapped ports appear as localhost_80, localhost_5001, etc. |
When your SUT calls downstream HTTP services, those calls must flow through TestTrackingMessageHandler to produce proper HTTP-style diagram arrows (with method, status code, headers, body). Do not mock service client interfaces and use MessageTracker to manually log HTTP interactions — this produces event-style (blue) arrows that are misleading.
Recommended approaches:
-
In-memory fake APIs —
WebApplicationFactoryinstances that serve canned responses (see Example.Api) -
JustEat HttpClient Interception — handler-level interception, chain with
TestTrackingMessageHandler -
WireMock.Net — real HTTP server on a random port, map in
PortsToServiceNames
See the Tracking Dependencies wiki page for detailed examples of each approach.
If you're migrating from the TestTrackingDiagrams.LightBDD.xUnit2 package, the key changes are:
| Aspect | xUnit 2 | xUnit 3 |
|---|---|---|
| Package | TestTrackingDiagrams.LightBDD.xUnit2 |
TestTrackingDiagrams.LightBDD.xUnit3 |
| LightBDD package | LightBDD.XUnit2 |
LightBDD.XUnit3 |
| xUnit package |
xunit (v2.x) |
xunit.v3 |
| Scope setup |
[assembly: ConfiguredLightBddScope] attribute |
[assembly: TestPipelineStartup(typeof(ConfiguredLightBddScope))] |
| Scope base class |
LightBddScopeAttribute (attribute) |
LightBddScope (class) |
| Parallelisation | [assembly: ClassCollectionBehavior(AllowTestParallelization = false)] |
Not needed (xUnit v3 handles this differently) |
| Output type | Library (default) |
<OutputType>Exe</OutputType> required |
| Namespace | TestTrackingDiagrams.LightBDD.xUnit2 |
TestTrackingDiagrams.LightBDD.xUnit3 |
All other concepts (FeatureFixture, Runner.RunScenarioAsync, CompositeStep, TrackingDiagramOverride, etc.) remain the same.
- Ensure
[assembly: TestPipelineStartup(typeof(ConfiguredLightBddScope))]is present at the top of your scope file. - Ensure
CreateStandardReportsWithDiagramsis called inOnConfigure. - Check that you have
<OutputType>Exe</OutputType>in your.csproj— xUnit v3 assemblies must be executable.
If any test has failed, the specifications files will be blank by design (they only generate on a fully passing test run). The FeaturesReport.html will still be generated.
Current versions of ReSharper may not recognise [assembly: TestPipelineStartup]. Use the Visual Studio Test Explorer or dotnet test instead.
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