xUnitV3LoadFramework 2.0.0.57

dotnet add package xUnitV3LoadFramework --version 2.0.0.57
                    
NuGet\Install-Package xUnitV3LoadFramework -Version 2.0.0.57
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="xUnitV3LoadFramework" Version="2.0.0.57" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="xUnitV3LoadFramework" Version="2.0.0.57" />
                    
Directory.Packages.props
<PackageReference Include="xUnitV3LoadFramework" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add xUnitV3LoadFramework --version 2.0.0.57
                    
#r "nuget: xUnitV3LoadFramework, 2.0.0.57"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package xUnitV3LoadFramework@2.0.0.57
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=xUnitV3LoadFramework&version=2.0.0.57
                    
Install as a Cake Addin
#tool nuget:?package=xUnitV3LoadFramework&version=2.0.0.57
                    
Install as a Cake Tool

xUnitV3LoadFramework

xUnit v3-native load-style test runner for executing actions concurrently over a duration and reporting throughput/success/failure.

NuGet Downloads .NET 8 xUnit v3 License: MIT

What It Is / What It Isn't

Best for:

  • CI performance smoke tests
  • Concurrency and regression checks
  • Integration-style load tests inside dotnet test
  • Quick validation that your API handles N concurrent requests

Not for:

  • Distributed load generation across machines
  • Protocol-specific clients (HTTP/2, gRPC, WebSocket)
  • Full observability platform with dashboards
  • Replacing dedicated load testing tools (k6, Locust, NBomber)

Install

dotnet add package xUnitV3LoadFramework

Quickstart

Attribute-Based

using xUnitV3LoadFramework.Attributes;
using xUnitV3LoadFramework.Extensions;

public class ApiLoadTests
{
    private static readonly HttpClient _httpClient = new();

    [Load(concurrency: 5, duration: 3000, interval: 500)]
    public async Task Api_Should_Handle_Concurrent_Requests()
    {
        var result = await LoadTestRunner.ExecuteAsync(async () =>
        {
            var response = await _httpClient.GetAsync("https://api.example.com/health");
            return response.IsSuccessStatusCode;
        });

        Assert.True(result.Success > 0);
        Assert.True(result.RequestsPerSecond > 1);
    }
}

Fluent API

using xUnitV3LoadFramework.Extensions;

public class ApiLoadTests
{
    private static readonly HttpClient _httpClient = new();

    [Fact]
    public async Task Api_Load_Test_Fluent()
    {
        var result = await LoadTestRunner.Create()
            .WithName("HealthCheck_Load")
            .WithConcurrency(10)
            .WithDuration(TimeSpan.FromSeconds(5))
            .WithInterval(TimeSpan.FromMilliseconds(200))
            .RunAsync(async () =>
            {
                var response = await _httpClient.GetAsync("https://api.example.com/health");
                response.EnsureSuccessStatusCode();
            });

        Assert.True(result.Success >= result.Total * 0.95);
    }
}

Sample Output

Load test 'HealthCheck_Load' completed:
  Total executions: 50
  Successful executions: 48
  Failed executions: 2
  Execution time: 5.12 seconds
  Requests per second: 9.77
  Average latency: 102.34ms
  Success rate: 96.00%

Core Concepts

Setting Description
Concurrency Number of concurrent operations launched per interval
Duration Total time the load test runs
Interval Time between launching batches of concurrent operations
TerminationMode How the test stops: Duration (immediate), CompleteCurrentInterval (finish current batch), or StrictDuration (exact timing)
GracefulStopTimeout Max time to wait for in-flight requests after duration expires. Default: 30% of duration, bounded 5-60s
Success Action returns true or completes without exception
Failure Action returns false or throws an exception
RequestsPerSecond Total / Time — completed operations per second

How Interval Works

Every Interval, the framework launches Concurrency concurrent operations. For example:

  • Concurrency: 5, Duration: 3s, Interval: 500ms = 6 batches × 5 operations = ~30 total operations

Advanced Configuration

Using LoadExecutionPlan Directly

For full control, use LoadExecutionPlan with LoadRunner.Run():

using LoadSurge.Models;
using LoadSurge.Runner;

[Fact]
public async Task Advanced_Load_Test()
{
    var plan = new LoadExecutionPlan
    {
        Name = "Database_Connection_Pool",
        Settings = new LoadSettings
        {
            Concurrency = 20,
            Duration = TimeSpan.FromSeconds(30),
            Interval = TimeSpan.FromMilliseconds(100),
            TerminationMode = TerminationMode.CompleteCurrentInterval,
            GracefulStopTimeout = TimeSpan.FromSeconds(10)
        },
        Action = async () =>
        {
            using var conn = new SqlConnection(connectionString);
            await conn.OpenAsync();
            return true;
        }
    };

    var result = await LoadRunner.Run(plan);

    Assert.True(result.Success >= result.Total * 0.99);
}

Termination Modes

Mode Behavior
Duration Stops immediately when duration expires (default)
CompleteCurrentInterval Waits for current batch to finish before stopping
StrictDuration Strict timing — may cut off final batch

MaxIterations (Fluent API)

Stop after a fixed number of operations regardless of duration:

var result = await LoadTestRunner.Create()
    .WithConcurrency(10)
    .WithDuration(TimeSpan.FromMinutes(5))
    .WithMaxIterations(1000) // Stop after 1000 operations
    .RunAsync(async () => { /* ... */ });

Assertions / CI Gating

Use LoadResult fields to fail tests based on performance criteria:

var result = await LoadTestRunner.Create()
    .WithConcurrency(10)
    .WithDuration(TimeSpan.FromSeconds(10))
    .RunAsync(async () => { /* ... */ });

// Success rate gate
var successRate = (double)result.Success / result.Total;
Assert.True(successRate >= 0.99, $"Success rate {successRate:P} below 99%");

// Throughput gate
Assert.True(result.RequestsPerSecond >= 50, $"RPS {result.RequestsPerSecond} below 50");

// Latency gate
Assert.True(result.Percentile95Latency < 500, $"P95 latency {result.Percentile95Latency}ms exceeds 500ms");
Assert.True(result.AverageLatency < 200, $"Avg latency {result.AverageLatency}ms exceeds 200ms");

Available Result Fields

  • Total, Success, Failure — counts
  • Time — execution time in seconds
  • RequestsPerSecond — throughput
  • AverageLatency, MinLatency, MaxLatency — in milliseconds
  • MedianLatency, Percentile95Latency, Percentile99Latency — percentiles in ms
  • PeakMemoryUsage — bytes

Safety & Gotchas

  • Thread-safety: Your action runs concurrently. Avoid shared mutable state unless protected.
  • Reuse HttpClient: Create a single static readonly HttpClient — don't instantiate per request.
  • Start low: Begin with low concurrency and short duration. Increase gradually.
  • Timeouts: Add your own timeout in the action. The framework won't kill hung operations:
    using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
    await httpClient.GetAsync(url, cts.Token);
    
  • Cancellation: The framework uses GracefulStopTimeout to wait for in-flight requests. Long-running actions without cancellation support may delay test completion.
  • CI filtering: Use dotnet test --filter "FullyQualifiedName~LoadTests" to run only load tests or exclude them from fast CI runs.

When to Choose This

Use this framework when:

  • You want load tests as part of dotnet test without extra tooling
  • You need quick concurrency smoke tests in CI
  • Your tests are integration-style (HTTP calls, database queries)
  • You want xUnit v3 native attributes and test discovery

Use a dedicated tool (k6, Locust, NBomber) when:

  • You need distributed load from multiple machines
  • You need protocol-specific features (HTTP/2 multiplexing, WebSocket)
  • You need real-time dashboards and detailed analytics
  • You're testing at scale (thousands of concurrent users)

Fun Explanation (optional)

Think of this like a playground stress test. You set:

  • How many kids play at once (Concurrency)
  • How long the playground is open (Duration)
  • How often new groups arrive (Interval)

The framework tells you how many kids had fun (success), how many fell off the swings (failure), and how fast the line moved (RPS).

Requirements

  • .NET 8.0+
  • xUnit v3

Contributing

PRs welcome. Open an issue for bugs or feature requests.


Made by Vasyl

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.0.57 22 12/13/2025
2.0.0.56 22 12/13/2025
2.0.0.55 184 12/5/2025
2.0.0.54 176 12/4/2025
2.0.0.53 648 12/1/2025
2.0.0.52 554 12/1/2025
2.0.0.51 275 11/16/2025
2.0.0.50 269 11/16/2025
2.0.0.49 268 11/16/2025
2.0.0.48 218 11/16/2025
2.0.0.47 204 11/14/2025
2.0.0.46 197 11/14/2025
2.0.0.45 200 11/14/2025
2.0.0.44 203 11/14/2025
2.0.0.43 203 11/14/2025
2.0.0.42 206 11/14/2025
2.0.0.41 179 10/22/2025
2.0.0.38 165 10/21/2025
2.0.0.36 178 9/12/2025
2.0.0.35 180 9/12/2025
2.0.0.27 388 8/5/2025
2.0.0.22 144 8/3/2025
2.0.0.21 148 8/3/2025
2.0.0.20 152 8/3/2025
2.0.0.19 148 8/3/2025
1.0.0.95 67 8/2/2025
1.0.0.94 59 8/1/2025
1.0.0.93 61 8/1/2025
1.0.0.92 138 7/29/2025
1.0.0.91 147 7/28/2025
1.0.0.90 143 7/28/2025
1.0.0.87 369 7/25/2025
1.0.0.86 369 7/25/2025
1.0.0.85 499 7/24/2025
1.0.0.84 490 7/24/2025
1.0.0.83 544 7/23/2025
1.0.0.81 549 7/22/2025
1.0.0.80 542 7/22/2025
1.0.0.79 547 7/22/2025
1.0.0.78 546 7/22/2025
1.0.0.77 551 7/22/2025
1.0.0.76 180 7/7/2025
1.0.0.75 169 7/7/2025
1.0.0.74 103 7/5/2025
1.0.0.73 277 5/12/2025
1.0.0.72 233 5/11/2025
1.0.0.71 218 5/11/2025
1.0.0.70 126 5/9/2025
1.0.0.69 121 5/9/2025
1.0.0.68 120 5/9/2025
1.0.0.67 130 5/9/2025
1.0.0.66 132 5/9/2025
1.0.0.65 133 5/9/2025
1.0.0.64 167 5/9/2025
1.0.0.63 177 5/9/2025
1.0.0.62 187 4/30/2025
1.0.0.61 182 4/30/2025
1.0.0.60 180 4/30/2025
1.0.0.57 180 4/30/2025

Version 2.0.0: Full xUnit v3 compatibility, fluent API, enhanced performance metrics, and production-ready features. See CHANGELOG.md for complete details.