Search code examples
c#fluent-assertions

FluentAssertions for equality of objects graph with array - approximate equality


I am trying to write a set of tests for an API which returns a result in the following form

{
  "metrics": [
    {
      "key": "Metric1",
      "portfolios": [
        {
          "portfolioKey": "Portfolio1",
          "outputs": [
            1000000,
            1013785.999689,
            1040271.12363882
          ]
        }
      ]
    },
    {
      "key": "Metric2",
      "portfolios": [
        {
          "portfolioKey": "Portfolio1",
          "outputs": [
            1000000,
            986601.99318665,
            985925.470917517
          ]
        }
      ]
    }
  ]
}

As you can see the object returned has

  • An array of metric objects
  • Each metric has a key which identifies it
  • Each metric has a list if portfolios which will be the same for each metric returned
  • Each portfolio has a key which identifies it
  • Each portfolio within a metric has an array of doubles called outputs.

It is really this nested array of doubles that I'm trying to test, I need to compare the outputs for a given metric/portfolio combination. However I only want to test approximate equality. For the sake of this question lets say I want the expected results to match the actual within 0.1

I am using Fluent Assertions, which has some pretty decent documentation on comparing object graphs, but I cannot seem to get this configured correctly.

Here is my code:

expectedMetrics.Should().BeEquivalentTo(actualMetrics, options =>
{
    options.Using<Metric>(m =>
    {
        m.Subject.Should().BeEquivalentTo(m.Subject, mo =>
        {
            mo.WithMapping<Metric>(x => x.Key, x => x.Key);
            mo.Using<Portfolio>(p =>
            {
                p.Should().BeEquivalentTo(p.Subject, po =>
                {
                    po.WithMapping<Portfolio>(x => x.PortfolioKey, x => x.PortfolioKey);
                    po.WithStrictOrderingFor(x => x.Outputs);
                    po.Including(x => x.Outputs).Using<double>(x =>
                    {
                        x.Subject.Should().BeApproximately(x.Expectation, 0.1);
                    });
                    return po;
                }); 
            });
            return mo;
        });
    });
    options.WithTracing();
    return options;
});

This seems to neither use my Mapping, nor use my approximate equality for the doubles. A small excerpt from the tracing says

Expected expectedMetrics.Metrics[0].Portfolios[0].Outputs[1] to be 1013785.9996890002, but found 1013785.999689.
Expected expectedMetrics.Metrics[0].Portfolios[0].Outputs[2] to be 1040271.1236388228, but found 1040271.12363882.

Which is clearly not checking to within 0.1. What am I doing wrong?


Solution

  • You need to pair Using<double>() with WhenTypeIs<double>().

    var subject = new[] { 1013785.999689, 1040271.12363882 };
    var expected = new[] { 1013785.9996890002, 1040271.1236388228 };
    
    subject.Should().BeEquivalentTo(expected, opt => opt
        .Using<double>(ctx => ctx.Subject.Should().BeApproximately(ctx.Expectation, 0.1))
        .WhenTypeIs<double>()
    );
    

    https://fluentassertions.com/objectgraphs/#equivalency-comparison-behavior