Fluent.Client.AwesomeAssertions 1.1.0

dotnet add package Fluent.Client.AwesomeAssertions --version 1.1.0
                    
NuGet\Install-Package Fluent.Client.AwesomeAssertions -Version 1.1.0
                    
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="Fluent.Client.AwesomeAssertions" Version="1.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Fluent.Client.AwesomeAssertions" Version="1.1.0" />
                    
Directory.Packages.props
<PackageReference Include="Fluent.Client.AwesomeAssertions" />
                    
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 Fluent.Client.AwesomeAssertions --version 1.1.0
                    
#r "nuget: Fluent.Client.AwesomeAssertions, 1.1.0"
                    
#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 Fluent.Client.AwesomeAssertions@1.1.0
                    
#: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=Fluent.Client.AwesomeAssertions&version=1.1.0
                    
Install as a Cake Addin
#tool nuget:?package=Fluent.Client.AwesomeAssertions&version=1.1.0
                    
Install as a Cake Tool

<div align="center"> <h1>๐Ÿงช Fluent.Client.AwesomeAssertions</h1> <h3><em>Write expressive HTTP assertions for .NET integration tests.</em></h3> </div>

<p align="center"> <strong>A fluent assertion library for <code>Task<HttpResponseMessage></code> that makes your HTTP tests readable, maintainable, and delightful to write.</strong> </p>

<p align="center"> <a href="https://www.nuget.org/packages/Fluent.Client.AwesomeAssertions"><img src="https://img.shields.io/nuget/v/Fluent.Client.AwesomeAssertions.svg" alt="NuGet"/></a> <a href="https://www.nuget.org/packages/Fluent.Client.AwesomeAssertions"><img src="https://img.shields.io/nuget/dt/Fluent.Client.AwesomeAssertions.svg" alt="NuGet Downloads"/></a> <a href="https://github.com/lepoco/fluent/stargazers"><img src="https://img.shields.io/github/stars/lepoco/fluent?style=social" alt="GitHub stars"/></a> <a href="https://github.com/lepoco/fluent/blob/main/LICENSE"><img src="https://img.shields.io/github/license/lepoco/fluent" alt="License"/></a> </p>

<p align="center"> <a href="https://lepo.co/">Created in Poland by Leszek Pomianowski</a> and <a href="https://github.com/lepoco/fluent/graphs/contributors">open-source community</a>. </p>


Table of Contents


๐Ÿค” Why This Library?

Traditional HTTP testing in .NET is verbose and hard to read:

// โŒ Traditional approach - verbose and unclear intent
var response = await client.PostAsync("/api/users", content);
Assert.True(response.IsSuccessStatusCode);
var body = await response.Content.ReadAsStringAsync();
var user = JsonSerializer.Deserialize<User>(body);
Assert.Equal("John", user.Name);

With Fluent.Client.AwesomeAssertions, your tests become expressive and self-documenting:

// โœ… Fluent approach - clear intent, readable assertions
await client
    .Post("/api/users", new { Name = "John" })
    .Should()
    .Satisfy<User>(u => u.Name.Should().Be("John"));

Fluent.Client is optional. This library works with standard HttpClient.PostAsync(), GetAsync(), etc.


โšก Get Started

1. Install the Package

dotnet add package Fluent.Client.AwesomeAssertions

๐Ÿ“ฆ NuGet: https://www.nuget.org/packages/Fluent.Client.AwesomeAssertions

2. (Optional) Add Fluent.Client

For an even more fluent API experience:

dotnet add package Fluent.Client

๐Ÿ“ฆ NuGet: https://www.nuget.org/packages/Fluent.Client

With Fluent.Client, you get extension methods like .Post(), .Get(), .Delete(), and .Authorize() directly on HttpClient.

3. Start Writing Tests

using Fluent.Client;
using Fluent.Client.AwesomeAssertions;

[Fact]
public async Task CreateUser_ReturnsSuccess()
{
    await client
        .Post("/api/users", new { Name = "John" })
        .Should()
        .Succeed("because valid user data was provided");
}

๐Ÿ“– How to Use

1. Assert Success

Assert that a request was successful (2xx status code).

<details> <summary><strong>Standard HttpClient</strong></summary>

await client
    .PostAsync("/api/users", content)
    .Should()
    .Succeed();

</details>

<details open> <summary><strong>With Fluent.Client</strong></summary>

await client
    .Post("/api/users", new { Name = "John" })
    .Should()
    .Succeed("because the server returned 200 OK");

</details>

The because parameter is optional but recommended for clearer test failure messages.


2. Assert Specific Status Code

Assert that a request returned a specific HTTP status code.

await client
    .Delete("/api/users/123")
    .Should()
    .HaveStatusCode(HttpStatusCode.NoContent, "because delete should return 204");
Quick Reference
Method Description
HaveStatusCode(HttpStatusCode) Asserts exact status code match
Succeed() Asserts any 2xx status code
Fail() Asserts any non-2xx status code

3. Assert Failure

Assert that a request failed (non-2xx status code).

await client
    .Post("/api/basket", new { CartItem = "esp32-dev-board" })
    .Should()
    .Fail("because the server returned 400 Bad Request");

Fail() passes for any non-success status code (4xx, 5xx). Use HaveStatusCode() if you need to verify a specific error code.


4. Assert Body Content

Assert on the deserialized response body using Satisfy<T>.

await client
    .Authorize(token: "abc123")
    .Get("/api/users/1", new 
    {
        // Query parameters as anonymous object
        includeDetails = true
    })
    .Should()
    .Satisfy<User>(user =>
    {
        user.Name.Should().Be("John");
        user.Id.Should().Be(1);
    }, "because the server returned the expected JSON body");

<details> <summary><strong>How it works</strong></summary>

  1. Awaits the HTTP response
  2. Reads the response body as string
  3. Deserializes JSON to T using System.Text.Json
  4. Executes your assertion lambda against the deserialized object

</details>

If the response body is not valid JSON or cannot be deserialized to T, the assertion will fail with a descriptive error message.


5. Authorization with Query Parameters

Combine authorization headers with query parameters for authenticated requests.

Bearer Token Authorization
await client
    .Authorize(token: "abc123")
    .Post("/v1/api/basket")
    .Should()
    .Succeed();
Basic Authentication
await client
    .Authorize(username: "john", password: "potato")
    .Get("/v1/api/basket", new
    {
        page = 1,
        limit = 2,
        sortBy = "dateAsc",
    })
    .Should()
    .HaveStatusCode(HttpStatusCode.Unauthorized, "because the credentials are invalid");
Authorization Methods
Method Header Format
.Authorize(token: "...") Authorization: Bearer {token}
.Authorize(username, password) Authorization: Basic {base64}

๐Ÿงช Integration Testing

The library excels in integration testing scenarios with multi-step workflows.

<details open> <summary><strong>Complete Workflow Example</strong></summary>

[Collection("Integration Tests")]
public sealed class OrderWorkflowTests(AspireAppHostFixture app)
{
    [Fact]
    public async Task Order_WhenCreatedAndProcessed_CompletesSuccessfully()
    {
        Guid orderId = Guid.NewGuid();

        // Step 1: Create resource
        await app.Client
            .Authorize(token: "jwt-token")
            .Put($"v1/orders/{orderId}", new { ProductId = "SKU-001", Quantity = 2 })
            .Should()
            .Succeed("because order creation should be accepted");

        // Step 2: Verify resource state
        await app.Client
            .Authorize(token: "jwt-token")
            .Get($"v1/orders/{orderId}")
            .Should()
            .Satisfy<OrderResponse>(order =>
            {
                order.Status.Should().Be("Pending");
                order.Id.Should().Be(orderId);
            });

        // Step 3: Transition state
        await app.Client
            .Authorize(token: "jwt-token")
            .Put($"v1/orders/{orderId}/confirm")
            .Should()
            .Succeed("because order confirmation should succeed");

        // Step 4: Complete workflow
        await app.Client
            .Authorize(token: "jwt-token")
            .Put($"v1/orders/{orderId}/complete", new { Note = "Delivered" })
            .Should()
            .Succeed("because order completion should succeed");
    }
}

</details>

Key Patterns

Pattern Description
๐Ÿ—๏ธ Test Fixtures Use WebApplicationFactory, AspireAppHostFixture, or similar for shared test setup
๐Ÿ”— Workflow Chaining Chain multiple API calls to test complete business flows
โœ… State Verification Use Satisfy<T> to verify intermediate states
๐Ÿ“ Descriptive Messages Add because messages for clear failure diagnostics

๐Ÿ“š API Reference

Assertion Methods

Method Description
Succeed() Asserts HTTP response has 2xx status code
Succeed(HttpStatusCode) Asserts HTTP response has specific success status code
Fail() Asserts HTTP response has non-2xx status code
HaveStatusCode(HttpStatusCode) Asserts HTTP response has exact status code
Satisfy<T>(Action<T>) Deserializes body and runs assertions on the result

JSON Serialization

<details> <summary><code>Satisfy<T></code> uses the following <code>JsonSerializerOptions</code> by default</summary>

new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true,
    AllowTrailingCommas = true,
    WriteIndented = true,
    IncludeFields = false,
    Converters = { new JsonStringEnumConverter() }
}

</details>


๐Ÿ‘ฅ Maintainers


๐Ÿ’ฌ Support

For support, please open a GitHub issue. We welcome bug reports, feature requests, and questions.


๐Ÿ™ Acknowledgements

This project builds on the excellent AwesomeAssertions library and is inspired by the need for better HTTP testing ergonomics in .NET.


๐Ÿ“„ License

This project is licensed under the terms of the MIT open source license. Please refer to the LICENSE file for the full terms.

You can use it in private and commercial projects. Keep in mind that you must include a copy of the license in your project.

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 is compatible.  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. 
.NET Framework net472 is compatible.  net48 was computed.  net481 is compatible. 
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
1.1.0 169 3/5/2026
1.0.2 192 2/6/2026
1.0.1 147 1/10/2026
1.0.0 115 1/9/2026
1.0.0-preview.1 102 1/9/2026