FluentAssertions - 如何使 ShouldBeEquivalentTo 比较空和 null 是否相等

FluentAssertions - how make ShouldBeEquivalentTo compare empty and null as equal

我正在使用 Fluent Assertion 库作为一些自定义序列化代码的单元测试的一部分,我正在寻找一种方法来强制 ShouldBeEquivalentTo 将 null 和空列表比较为相等。

基本上,我的测试类似于:

    [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);
    }

然而,反序列化方法的一个特点是,如果输入数据中缺少集合类型,它会将反序列化的 class 上的 属性 设置为一个空列表,而不是比空。因此,非常简单,我最终遇到的情况是实例二 Items = new List<string> 而不是 null.

显然,我可以在比较之前设置 one.Items = new List<string>(),但实际上我在这些方法中声明了大量复杂的域对象,我正在寻找一个通用的解决方案。换句话说,有谁知道如何通过以下测试:

    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);
    }

换句话说,我希望将以下测试应用于 class X 中的所有集合,作为比较等价性的一部分:

  if (subject.Items == null)
  {
     expected.Items.Should().BeEmpty();
  }
  else
  {
     expected.Items.Should().BeEquivalentTo(subject.Items);
  }

您必须实施自定义 'IEquivalencyStep' 或 u.se 'options.Using(自定义操作).WhenTypeIs(predicate).

根据上面 Dennis 提供的信息,我能够通过以下实际代码解决此问题:

    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)));
            }
        }
    }

创建 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();
    }
}

然后申请您的 BeEquivalentTo 电话:

actual.Should().BeEquivalentTo(expected, opt => opt.Using(new EnumerableNullEmptyEquivalenceRule()));