FluentAssertions - Actual body is not displayed in error message when using Json Body #588

Closed
opened 2025-12-29 08:30:38 +01:00 by adam · 6 comments
Owner

Originally created by @srollinet on GitHub (Mar 18, 2024).

Describe the bug

When using a Json Body, Fluent assertion cannot format the actual body in the error message

Expected wiremockserver to have been called using body { param = value2 }, but didn't find it among the body {{{{empty}}}}.

Expected behavior:

The json body is correctly formatted

Expected wiremockserver to have been called using body { param = value2 }, but didn't find it among the body {{
"param": "value"
}}.

Test to reproduce

You can reproduce the message with this unit test (proper assertion is not done, the test fails with the unformatted message)

    [Fact]
    public async Task HaveReceived1Call_WithBodyAsJson_UsingJsonMatcher()
    {
        // Arrange
        var server = WireMockServer.Start();

        server
            .Given(Request.Create().WithPath("/a").UsingPost())
            .RespondWith(Response.Create().WithBody("A response"));

        // Act
        var httpClient = new HttpClient();

        var body = new
        {
            param = "value"
        };
        await httpClient.PostAsJsonAsync($"{server.Url}/a", body);

        body = new
        {
            param = "value2"
        };
        // Assert
        server
            .Should()
            .HaveReceived(1)
            .Calls()
            .WithBodyAsJson(new JsonMatcher(body))
            .And
            .UsingPost();

        server.Stop();
    }

One solution is to implement a custom IValueFormatter

Example:

public class JObjectFormatter : IValueFormatter
{
    public bool CanHandle(object value)
    {
        return value is JObject;
    }

    public void Format(object value, FormattedObjectGraph formattedGraph, FormattingContext context, FormatChild formatChild)
    {
        var jObject = (JObject)value;
        formattedGraph.AddFragment(jObject.ToString());
    }
}

And to add it in the custom formatters Formatter.AddFormatter(new JObjectFormatter());

Note: the IValueFormatter interface varies based on the target framework, so it must be multiple implementations

Let me know if I can help or if I can make a PR for this issue

Originally created by @srollinet on GitHub (Mar 18, 2024). ### Describe the bug When using a Json Body, Fluent assertion cannot format the actual body in the error message > Expected wiremockserver to have been called using body { param = value2 }, but didn't find it among the body {{{{empty}}}}. ### Expected behavior: The json body is correctly formatted > Expected wiremockserver to have been called using body { param = value2 }, but didn't find it among the body {{ "param": "value" }}. ### Test to reproduce You can reproduce the message with this unit test (proper assertion is not done, the test fails with the unformatted message) ```cs [Fact] public async Task HaveReceived1Call_WithBodyAsJson_UsingJsonMatcher() { // Arrange var server = WireMockServer.Start(); server .Given(Request.Create().WithPath("/a").UsingPost()) .RespondWith(Response.Create().WithBody("A response")); // Act var httpClient = new HttpClient(); var body = new { param = "value" }; await httpClient.PostAsJsonAsync($"{server.Url}/a", body); body = new { param = "value2" }; // Assert server .Should() .HaveReceived(1) .Calls() .WithBodyAsJson(new JsonMatcher(body)) .And .UsingPost(); server.Stop(); } ``` ### Other related info One solution is to implement a custom `IValueFormatter` Example: ```cs public class JObjectFormatter : IValueFormatter { public bool CanHandle(object value) { return value is JObject; } public void Format(object value, FormattedObjectGraph formattedGraph, FormattingContext context, FormatChild formatChild) { var jObject = (JObject)value; formattedGraph.AddFragment(jObject.ToString()); } } ``` And to add it in the custom formatters `Formatter.AddFormatter(new JObjectFormatter());` Note: the `IValueFormatter` interface varies based on the target framework, so it must be multiple implementations Let me know if I can help or if I can make a PR for this issue
adam added the bug label 2025-12-29 08:30:38 +01:00
adam closed this issue 2025-12-29 08:30:38 +01:00
Author
Owner

@StefH commented on GitHub (Mar 18, 2024):

@srollinet
Could it also be an option to just create a helper method in WireMockAssertions.WithBody.cs which formats all possible body values?

@StefH commented on GitHub (Mar 18, 2024): @srollinet Could it also be an option to just create a helper method in `WireMockAssertions.WithBody.cs` which formats all possible body values?
Author
Owner

@srollinet commented on GitHub (Mar 18, 2024):

It could also probably be an option. I can check that next day if you want.

@srollinet commented on GitHub (Mar 18, 2024): It could also probably be an option. I can check that next day if you want.
Author
Owner

@StefH commented on GitHub (Mar 18, 2024):

Sure. A PR is welcome.

@StefH commented on GitHub (Mar 18, 2024): Sure. A PR is welcome.
Author
Owner

@srollinet commented on GitHub (Mar 19, 2024):

Okay, doing something like this makes the message better

    public AndConstraint<WireMockAssertions> WithBodyAsJson(IObjectMatcher matcher, string because = "", params object[] becauseArgs)
    {
        var (filter, condition) = BuildFilterAndCondition(r => r.BodyAsJson, matcher);

        return ExecuteAssertionWithBodyAsIObjectMatcher(matcher, because, becauseArgs, condition, filter, r => FormatBody(r.BodyAsJson));
    }

    private static object? FormatBody(object? body)
    {
        if (body is JToken jToken)
        {
            return jToken.ToString(Formatting.None);
        }
        
        //TODO Add other types here

        return body;
    }

Expected wiremockserver to have been called using body { param = value2, otherParam = 18067588-16df-4f27-ab2b-a737206f97ff }, but didn't find it among the body {"{"param":"value","otherParam":42}"}.

But it is still different between the expected body and the actual body

And it is worse if the Matcher is created by using a named type, or even worse if the type overrides ToString()

Expected wiremockserver to have been called using body WireMock.Net.Tests.FluentAssertions.WireMockAssertionsTests+RequestInputDto
{
OtherParam = {718de8cd-21ef-4406-b631-1cd99c1a4328},
Param = "value"
}, but didn't find it among the body {"{"Param":"value","OtherParam":"6d3380ff-bfcf-4269-8d81-01ac24d13645"}"}.

I wonder if the expected body should also be serialized as json, so both representations will be similar. What do you think?

@srollinet commented on GitHub (Mar 19, 2024): Okay, doing something like this makes the message better ```cs public AndConstraint<WireMockAssertions> WithBodyAsJson(IObjectMatcher matcher, string because = "", params object[] becauseArgs) { var (filter, condition) = BuildFilterAndCondition(r => r.BodyAsJson, matcher); return ExecuteAssertionWithBodyAsIObjectMatcher(matcher, because, becauseArgs, condition, filter, r => FormatBody(r.BodyAsJson)); } private static object? FormatBody(object? body) { if (body is JToken jToken) { return jToken.ToString(Formatting.None); } //TODO Add other types here return body; } ``` > Expected wiremockserver to have been called using body { param = value2, otherParam = 18067588-16df-4f27-ab2b-a737206f97ff }, but didn't find it among the body {"{"param":"value","otherParam":42}"}. But it is still different between the expected body and the actual body And it is worse if the Matcher is created by using a named type, or even worse if the type overrides `ToString()` > Expected wiremockserver to have been called using body WireMock.Net.Tests.FluentAssertions.WireMockAssertionsTests+RequestInputDto { OtherParam = {718de8cd-21ef-4406-b631-1cd99c1a4328}, Param = "value" }, but didn't find it among the body {"{"Param":"value","OtherParam":"6d3380ff-bfcf-4269-8d81-01ac24d13645"}"}. I wonder if the expected body should also be serialized as json, so both representations will be similar. What do you think?
Author
Owner

@StefH commented on GitHub (Mar 19, 2024):

@srollinet
Can you take a look at my PR ?

@StefH commented on GitHub (Mar 19, 2024): @srollinet Can you take a look at my PR ?
Author
Owner

@srollinet commented on GitHub (Mar 19, 2024):

@StefH Yes, it looks good to me

@srollinet commented on GitHub (Mar 19, 2024): @StefH Yes, it looks good to me
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/WireMock.Net#588