I try to get started with FluentAssertions but quite soon I ran in a problem. I use it along with MSTest. The test below fails what shouldn´t happen (from my point of view).
[TestMethod]
public void DoubleTest()
{
double temp1 = 0.1 - 0.025;
double temp2 = 0.075;
temp1.ShouldBeEquivalentTo(temp2, options => options.Using<double>
(a => a.Subject.HasMinimalDifference(a.Expectation, 1)).WhenTypeIs<double>());
}
public static bool HasMinimalDifference(double value1, double value2, int units)
{
long lValue1 = BitConverter.DoubleToInt64Bits(value1);
long lValue2 = BitConverter.DoubleToInt64Bits(value2);
// If the signs are different, return false except for +0 and -0.
if ((lValue1 >> 63) != (lValue2 >> 63))
{
if (value1 == value2)
return true;
return false;
}
long diff = Math.Abs(lValue1 - lValue2);
if (diff <= (long) units)
return true;
return false;
}
I did quite some research but my impression is that Fluent Assertions ignores a custom double comparer. Or is it just me? I really want to use a custom double comparer as this might get extended beyound the MS-example above in the future. Any help would be appreciated.
Two things seems to be going on here.
1)
Using
expects an action doing an assertion.
Using<TProperty>(Action<IAssertionContext<TProperty>> action)
You can workaround that by using HasMinimalDifference(a.Subject, a.Expectation, 1).Should().BeTrue()
.
2)
Since you're using ShouldBeEquivalentTo
you must be running v4.19.4 or older since we removed that method in v5.
I can reproduce the bug in v4.19.4.
You're hitting a bug where custom assertions were not applied on the root object. The bug was fixed in https://github.com/fluentassertions/fluentassertions/pull/1033 and released as part of v5.7.0.
[TestMethod]
public void DoubleTest()
{
object temp1 = 0.1 - 0.025;
object temp2 = 0.075;
temp1.Should().BeEquivalentTo(temp2, options => options
.Using<double>(a => HasMinimalDifference(a.Subject, a.Expectation, 1).Should().BeTrue())
.WhenTypeIs<double>());
}
public static bool HasMinimalDifference(double value1, double value2, int units)
{
long lValue1 = BitConverter.DoubleToInt64Bits(value1);
long lValue2 = BitConverter.DoubleToInt64Bits(value2);
// If the signs are different, return false except for +0 and -0.
if ((lValue1 >> 63) != (lValue2 >> 63))
{
if (value1 == value2)
return true;
return false;
}
long diff = Math.Abs(lValue1 - lValue2);
if (diff <= (long)units)
return true;
return false;
}
I haven't looked into what HasMinimalDifference
computes, but here's the idiomatic way to perform a relaxed comparison for all doubles.
Docs
[TestMethod]
public void DoubleTest()
{
object temp1 = 0.1 - 0.025;
object temp2 = 0.075;
temp1.Should().BeEquivalentTo(temp2, options => options
.Using<double>(a => a.Subject.Should().BeApproximately(a.Expectation, 1))
.WhenTypeIs<double>());
}