pact-foundation / pact-net

.NET version of Pact. Enables consumer driven contract testing, providing a mock service and DSL for the consumer project, and interaction playback and verification for the service provider project.
https://pact.io
MIT License
842 stars 231 forks source link

Matching fails on double / float / decimal with integer value #464

Closed Manny651 closed 1 year ago

Manny651 commented 1 year ago

When a match condition is a decimal number with an integer value, there is a verification mismatch when the JSON value is represented by a integer.

Example:

var pact = Pact.V3("My API", "Consumer").WithHttpInteractions();
var body = new { value = 10m };

pact.UponReceiving("A request with decimals")
    .WithRequest(HttpMethod.Post, "/test")
    .WithJsonBody(body)
    .WillRespond()
    .WithStatus(HttpStatusCode.OK);

pact.Verify(context =>
{
    var client = new HttpClient { BaseAddress = context.MockServerUri };
    client.PostAsJsonAsync("/test", body).Wait();
});

Gives Verification mismatches:

{"actual":"10","expected":"10.0","mismatch":"Expected '10.0' to be equal to '10'","path":"$.value","type":"BodyMismatch"}

It looks like the library expects the decimals to be serialized by Json.NET (which always serializes floats and decimals with a decimal point), unlike System.Text.Json or other frameworks.

adamrodger commented 1 year ago

This is expected behaviour that's been that way ever since the first version. It's a difference between JSON's unified number type and the fact that C# differentiates all those different types.

If we didn't do that then the interactions could be brittle if one side uses integers and the other floating point values. For example, you may start getting truncated values deserialised to integers when the provider sends decimals.

You need to ensure that any floating point numbers contain a fractional element so that it can be ensured both sides are using floating point.