1

I noticed with the latest nuget package (FluentAssertions -Version 5.6.0) I still can't see the ShouldBeEquivalentTo method to do the object comparison without value (ONLY the structure). I can see Should().BeEquivalentTo() but not sure how to do assert object structure except values.

My solution is on .Net Core 2.1

My code:

[Fact]
        public void GetFlatTariffForOneProduct_ReturnSuccess()
        {
            this.Given(_ => _steps.GivenACorrelationIdHeaderIsProvided(true))
                .And(_ => _steps.TheFlatTariffRawDataInDb(1))
                .When(_ => _steps.WhenTheRequestExecutes(_endpoint, new EstimationRequestBuilder().FlatRateElecRequest().Build()))
                .Then(_ => _steps.TheResponseCodeIs(HttpStatusCode.OK))
                .And(_ => _steps.TheReturnedContentIs(new EstimationResponseBuilder().EstimateResponse(1).Build()))
                .BDDfy();
        }

The last step of the above is called method below to assert the object model without data.

public async Task TheReturnedContentIs<T>(T obj)
        {
            var responseString = await ResponseMessage.Content.ReadAsStringAsync();
            var deserializeObject = JsonConvert.DeserializeObject<T>(responseString);
            obj.Should().BeEquivalentTo(deserializeObject);

        }

Expected response:

{
    "attributeA": {
        "attribute2": "CITIPP",
        "attribute3": [
            {
                "attribute4": "Variable",
                "attribute5": {
                    "attribute6": 65.5022916666667,
                    "attribute7": 45.407291666666673,
                    "attribute8": 33.454791666666679
                }
            },
            {
                "attribute4": "Fixed",
                "attribute5": {
                    "attribute6": 21.8762916666667,
                    "attribute7": 89.432291666666673,
                    "attribute8": 90.236791666666679
                }
            }
        ]
    },
    "attributeB": {
        "attribute2": "CITIPP",
        "attribute3": [
            {
                "attribute4": "Variable",
                "attribute5": {
                    "attribute6": 71.5022916666667,
                    "attribute7": 53.407291666666673,
                    "attribute8": 62.454791666666679
                }
            },
            {
                "attribute4": "Fixed",
                "attribute5": {
                    "attribute6": 38.5022916666667,
                    "attribute7": 53.407291666666673,
                    "attribute8": 44.3684791666666679
                }
            }
        ]
    }
}

With the assertion below actual response should pass. As you noticed structure is same not the values. But if any of the attribute name is different assertion should fail. (e.g. if attributeA changed to attributeX in the response)

Actual Response

{
    "attributeA": {
        "attribute2": "ABCD",
        "attribute3": [
            {
                "attribute4": "Variable",
                "attribute5": {
                    "attribute6": 71.5022916666667,
                    "attribute7": 53.407291666666673,
                    "attribute8": 62.454791666666679
                }
            },
            {
                "attribute4": "Fixed",
                "attribute5": {
                    "attribute6": 71.5022916666667,
                    "attribute7": 53.407291666666673,
                    "attribute8": 62.454791666666679
                }
            }
        ]
    },
    "attributeB": {
        "attribute2": "CITIPP",
        "attribute3": [
            {
                "attribute4": "Variable",
                "attribute5": {
                    "attribute6": 54.5022916666667,
                    "attribute7": 11.407291666666673,
                    "attribute8": 98.454791666666679
                }
            },
            {
                "attribute4": "Fixed",
                "attribute5": {
                    "attribute6": 71.222916666667,
                    "attribute7": 53.33291666666673,
                    "attribute8": 32.454791666666679
                }
            }
        ]
    }
}

I pass the object model to the above method. So I expect to compare the object structure without the values. The reason for above assertion failure due to value differences. The structure is matched perfectly.

Shabar
  • 2,617
  • 11
  • 57
  • 98
  • 1
    `ShouldBeEquivalentTo` was removed in v5.0.0 https://www.continuousimprover.com/2018/02/fluent-assertions-50-best-unit-test.html#redefining-equivalency For help regarding your specific comparison problem, please post a [Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve) – Jonas Nyrup Feb 26 '19 at 07:02
  • it worked with this `obj.Should().Equals(deserializeObject);`. Not sure anything better is out there. – Shabar Feb 26 '19 at 09:55
  • 1
    Doesn't `obj.Should().Equals()` resolve to `Object.Equals(object)`? – Jonas Nyrup Feb 26 '19 at 10:05
  • @JonasNyrup It does. – Shabar Feb 26 '19 at 10:15
  • Then you're no longer asserting anything? – Jonas Nyrup Feb 27 '19 at 20:59
  • @JonasNyrup Sorry what I meant was `obj.Equals(deserializeObject);` is same as `obj.Should().Equals(deserializeObject);` – Shabar Feb 28 '19 at 03:27
  • No, it's not. The first checks if `obj` and `deserializeObject` are equal. The second checks if `obj.Should()`, which is an instance of `ObjectAssertions`, and `deserializeObject` are equal. – Jonas Nyrup Feb 28 '19 at 07:21
  • @JonasNyrup Both the occasions no assertion failures. Tests are green. As per your explanation the correct assertion should be `obj.Equals(deserializeObject)` based on the code in the question? – Shabar Feb 28 '19 at 09:55
  • This seems to assert only the structure, `obj.Should().BeEquivalentTo(deserializeObject, options => options .ExcludingFields() .ExcludingProperties());` – Shabar Feb 28 '19 at 10:47
  • I haven't said what it _should_ be, only what it _should not_ be. Please post a _complete_ example to show what you're trying to archive. – Jonas Nyrup Feb 28 '19 at 11:51
  • @JonasNyrup I have updated the question with full test. – Shabar Mar 01 '19 at 22:57
  • I'm sorry, but it's still not complete. Complete, as described [here](https://stackoverflow.com/help/mcve), means that one can copy/paste it directly into e.g. Visual Studio and run it. Try to explain what you mean with comparing structure without comparing value. Do have some concrete examples of when the desired should pass and when you want it to fail? – Jonas Nyrup Mar 02 '19 at 09:18
  • @JonasNyrup Hope it makes more sense now. – Shabar Mar 02 '19 at 22:56

1 Answers1

2

What you can do is to traverse the two object graphs as BeEquivalentTo normally does, but ignoring all strings and numeric types by considering any two instances as being equal.

Here's an example that should do that.

T expected = JsonConvert.DeserializeObject<T>(expectedJSON);
T actual = JsonConvert.DeserializeObject<T>(actualJSON);

actual.Should().BeEquivalentTo(expected, opt => opt
    .Using<object>(_ => { })
    .When(e => e.RuntimeType.IsValueType)
    .Using<string>(_ => { })
    .WhenTypeIs<string>())

Read more in the documentation: https://fluentassertions.com/objectgraphs/#equivalency-comparison-behavior

Jonas Nyrup
  • 2,376
  • 18
  • 25