将IEnumerable(使用收益率回报)与其自身进行比较时,Assert.Equal()失败

时间:2019-06-14 11:26:30

标签: c# ienumerable xunit

为我的代码编写单元测试时遇到以下问题。为什么将IEnumerable与自身进行比较时Assert.Equal()失败?

private class ReferenceType { }

[Fact]
public void EnumerableEqualityTest()
{
    IEnumerable<ReferenceType> GetEnumerable()
    {
        yield return new ReferenceType();
    }

    var enumerable = GetEnumerable();

    Assert.Equal(enumerable, enumerable); // fails
}

2 个答案:

答案 0 :(得分:1)

要了解正在发生的事情,我们需要了解Assert.Equal()实际在做什么。根据{{​​1}}的文档,它“使用默认比较器验证两个序列是否相等”。

在这种情况下,Assert.Equal<T>(IEnumerable<T> expected, IEnumerable<T> actual)迭代枚举,以检查各个值是否相等。这意味着可枚举被迭代两次以进行比较,并且每次(通过yield return)都会创建一个Assert.Equal()的新实例。测试失败,因为引用类型的默认比较器仅检查实例是否引用同一对象。

至少有三种方法可获得预期结果:

  1. ReferenceType使用重载,该重载采用Assert.Equal()的参数。
  2. 覆盖IEqualityComparer<T>的{​​{1}}方法。
  3. 跳过Equals(),而使用实现ReferenceType的集合。

可以说第一个解决方案是最好的,因为它不会更改yield returnIEnumerable的实现。在仅在测试中使用GetEnumerable()的情况下,我会选择第三个选项,因为它最容易做到。看起来可能像这样:

ReferenceType

或者这个:

GetEnumerable()

之所以可行,是因为我们现在迭代获得枚举时创建的集合,而不是为每次迭代创建新实例。

答案 1 :(得分:0)

我认为,您可以使用以下功能解决问题。

public bool AreEquivalentEnumerator(IEnumerator<TSource> first, IEnumerator<TSource> second)
        {
            while (first.MoveNext())
            {
                if (!(second.MoveNext() && Equals(first.Current, second.Current))) return false;
            }

            if (second.MoveNext()) return false;

            return true;
        }