Providing an extension to FluentAssertions
Asked Answered
P

1

6

Because I have some angles, I would like to check for an angle modulus 360°:

    double angle = 0;
    double expectedAngle = 360;
    angle.Should().BeApproximatelyModulus360(expectedAngle, 0.01);

I have written an extension to the Fluent Assertions framework following a tutorial : https://fluentassertions.com/extensibility/

public static class DoubleExtensions
{
  public static DoubleAssertions Should(this double d)
  {
    return new DoubleAssertions(d);
  }
}


public class DoubleAssertions : NumericAssertions<double>
{
  public DoubleAssertions(double d) : base(d)
  {
  }
  public AndConstraint<DoubleAssertions> BeApproximatelyModulus360(
      double targetValue, double precision, string because = "", params object[] becauseArgs)
  {
    Execute.Assertion
        .Given(() => Subject)
        .ForCondition(v => MathHelper.AreCloseEnoughModulus360(targetValue, (double)v, precision))
        .FailWith($"Expected value {Subject}] should be approximatively {targetValue} with {precision} modulus 360");
    return new AndConstraint<DoubleAssertions>(this);
}

When I use both namespaces :

using FluentAssertions;
using MyProjectAssertions;

Because I also use :

 aDouble.Should().BeApproximately(1, 0.001);

I get following compilation error : Ambiguous call between 'FluentAssertions.AssertionExtensions.Should(double)' and 'MyProjectAssertions.DoubleExtensions.Should(double)'

How to change my code to extend the standard NumericAssertions (or other suitable class) to have my BeApproximatelyModulus360 next to the standard BeApproximately ?

Thanks

Plainspoken answered 24/2, 2021 at 21:3 Comment(3)
Remove the using... statement for one of namespaces or call the method directly MyProjectAssertions.DoubleExtensions.Should(yourDouble)Shelbashelbi
Of course ! You're right. But I expected a shorter way to write. Because it makes my call like FluentAssertions.DoubleExtensions.Should(luminanceComputation.Beta).BeApproximatelyModulus360(0,0.01); - to be compared to : Assert.True(MathHelper.AreCloseEnoughModulus360(0, luminanceComputation.Beta,0.01)); - that is no more very Fluent.Plainspoken
And actually there are some other naming conflicts that I am just experiencing that prevents using my new assertion Api the standard FluentAssertion onePlainspoken
P
9

If you want to directly access the extension method on a double object, and not on a DoubleAssertion object, why introduce the complexity of even creating a new type DoubleAssertion. Instead, define an extension method directly for NumericAssertions<double>.

  public static class DoubleAssertionsExtensions
    {
        public static AndConstraint<NumericAssertions<double>> BeApproximatelyModulus360(this NumericAssertions<double> parent,
            double targetValue, double precision, string because = "", params object[] becauseArgs)
        {
            Execute.Assertion
                .Given(() => parent.Subject)
                .ForCondition(v => MathHelper.AreCloseEnoughModulus360(targetValue, (double)v, precision))
                .FailWith(
                    $"Expected value {parent.Subject}] should be approximatively {targetValue} with {precision} modulus 360");
            return new AndConstraint<NumericAssertions<double>>(parent);
        }
    }

And then you can use them together.

 public class Test
    {
        public Test()
        {
            double aDouble = 4;

            aDouble.Should().BeApproximately(1, 0.001);
            aDouble.Should().BeApproximatelyModulus360(0, 0.1);

        }
    }
Plumbing answered 24/2, 2021 at 21:35 Comment(1)
Thank you very much Marshal, you helped me find clarity that I lostPlainspoken

© 2022 - 2024 — McMap. All rights reserved.