Reputation: 1871
I am trying to compare two list of objects with FluentAssertions. The objects have a property stored as a double that may be off by a small amount. Is there an efficient way to do this without iterating through the lists? My current method looks like
actualList.ShouldAllBeEquivalentTo(expectedList, options => options.Excluding(o => o.DoubleProperty));
for (var i = 0; i < actualList.Count; i++)
{
actualList[i].DoubleProperty
.Should().BeApproximately(expectedList[i].DoubleProperty, precision);
}
Which is a little ugly and irritating as this issue keeps on coming up. Another possibility (inspired by Fluent Assertions: Compare two numeric collections approximately) is
actualList.Select(o => o.DoubleProperty)
.Should().Equal(expectedList.Select(o => o.DoubleProperty),
(left, right) => AreEqualApproximately(left, right, precision));
Where I would write the AreEqualApproximately
function myself. If possible, I would like to do the comparison without defining my own helper methods or iterating through the lists by index.
Upvotes: 2
Views: 1211
Reputation: 1871
Based on Fluent Assertions: Approximately compare a classes properties
actualList.ShouldAllBeEquivalentTo(
expectedList,
options => options.Using<double>(d => d.Subject.Should().BeApproximately(d.Expectation, precision))
.WhenTypeIs<double>()
Turns out to work the best for me, although because I have to do this several times, I ended up changing the options for FluentAssertions globally in TestInitialize
.
Upvotes: 1
Reputation: 247088
The following should also work using the options available in ShouldAllBeEquivalentTo
actualList.ShouldAllBeEquivalentTo(expectedList, options => options
.Using<double>(ctx => ctx.Subject.Should()
.BeApproximately(ctx.Expectation, precision))
.When(o => o.SelectedMemberPath == "DoubleProperty"));
Upvotes: 2
Reputation: 3880
You can create extension methods that will merge your actual and expected values into a single list and foreach over them:
public static class ExtensionMethods
{
public static IEnumerable<ValueTuple<T, T>> Merge<T>(this List<T> a, List<T> b)
{
for (int x = 0, y = 0; x < a.Count && y < a.Count; x++, y++)
{
yield return ValueTuple.Create(a[x], b[y]);
}
}
public static void ForEach<T>(this IEnumerable<T> s, Action<T> m)
{
foreach (var i in s) m(i);
}
}
Then, you can use it like this:
actualList.Merge(expectedList)
.ForEach(i =>
i.Item1.DoubleProperty
.Should().BeApproximately(i.Item2.DoubleProperty, precision));
Upvotes: 1