I am using Fluent Assertion library as part of my unit tests for some custom serialization code and I am looking for a way to force ShouldBeEquivalentTo to compare as equal a null and empty list.
Basically, my tests look something like:
[Test]
public void Should_be_xxx()
{
ClassWithList one = new ClassWithList { Id = "ten", Items = null };
string serialized = Serialize(one);
ClassWithList two = Deserialize(serialized);
two.ShouldBeEquivalentTo(one);
}
However, one of the features of the Deserialize method is that if a collection type is missing in the input data, it sets the property on the deserialized class to an empty list, rather than null. So, very simplified, I end up with a situation where in instance two, Items = new List<string>
rather than null.
Obviously, I could set one.Items = new List<string>()
before comparing, but in reality I have a large number of complex domain objects that I am asserting in these methods and I am looking for a general solution. To put it another way, does anyone know how to make the following test pass:
public class ClassWithList
{
public string Id { get; set; }
public List<string> Items { get; set; }
}
[Test]
public void Should_be_xxx()
{
ClassWithList one = new ClassWithList { Id = "ten", Items = null };
ClassWithList two = new ClassWithList { Id = "ten", Items = new List<string>() };
two.ShouldBeEquivalentTo(one);
}
To put it another way, I am looking to apply the following test to all collections in a class X as part of comparing equivalence:
if (subject.Items == null)
{
expected.Items.Should().BeEmpty();
}
else
{
expected.Items.Should().BeEquivalentTo(subject.Items);
}
Based on the information from Dennis above, I was able to solve this will the following actual code:
public class ClassWithList
{
public string Id { get; set; }
public List<string> Items { get; set; }
public List<ClassWithList> Nested { get; set; }
}
[TestClass]
public class Test
{
[TestMethod]
public void Should_compare_null_to_empty()
{
ClassWithList one = new ClassWithList { Id = "ten", Items = null, Nested = new List<ClassWithList> { new ClassWithList { Id = "a" } } };
ClassWithList two = new ClassWithList { Id = "ten", Items = new List<string>(), Nested = new List<ClassWithList> { new ClassWithList { Id = "a", Items = new List<string>(), Nested = new List<ClassWithList> { } } } };
two.ShouldBeEquivalentTo(one, opt => opt
.Using<IEnumerable>(CheckList)
.When(info => typeof(IEnumerable).IsAssignableFrom(info.CompileTimeType)));
}
private void CheckList(IAssertionContext<IEnumerable> a)
{
if (a.Expectation == null)
{
a.Subject.Should().BeEmpty();
}
else
{
a.Subject.ShouldBeEquivalentTo(a.Expectation, opt => opt
.Using<IEnumerable>(CheckList)
.When(info => typeof(IEnumerable).IsAssignableFrom(info.CompileTimeType)));
}
}
}
You'll have to implement a custom 'IEquivalencyStep' or u.se 'options.Using(custom action).WhenTypeIs(predicate).
Create an IAssertionRule
:
public class EnumerableNullEmptyEquivalenceRule : IAssertionRule
{
public bool AssertEquality(IEquivalencyValidationContext context)
{
// not applicable - return false
if (!typeof(IEnumerable).IsAssignableFrom(context.SelectedMemberInfo.MemberType)) return false;
return context.Expectation == null && ((IEnumerable)context.Subject).IsNullOrEmpty();
}
}
Then apply to your BeEquivalentTo
call:
actual.Should().BeEquivalentTo(expected, opt => opt.Using(new EnumerableNullEmptyEquivalenceRule()));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With