Assert.Equal () завершается ошибкой при сравнении IEnumerable (с использованием yield return) с самим собой - PullRequest
0 голосов
/ 14 июня 2019

При написании модульного теста для моего кода возникла следующая проблема. Почему Assert.Equal () завершается ошибкой при сравнении IEnumerable с самим собой?

private class ReferenceType { }

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

    var enumerable = GetEnumerable();

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

Ответы [ 2 ]

1 голос
/ 14 июня 2019

Чтобы понять, что происходит, нам нужно понять, что на самом деле делает Assert.Equal(). Согласно документации Assert.Equal<T>(IEnumerable<T> expected, IEnumerable<T> actual) он «Проверяет, что две последовательности эквивалентны, используя компаратор по умолчанию».

Assert.Equal() в этом случае перебирает перечисляемое значение, чтобы проверить, равны ли отдельные значения. Это означает, что перечисляемое значение повторяется дважды для сравнения, и каждый раз создается новый экземпляр ReferenceType (с помощью возврата доходности). Тест не пройден, поскольку компаратор по умолчанию для ссылочного типа только проверяет, ссылаются ли экземпляры на один и тот же объект.

Есть как минимум три способа получить ожидаемый результат:

  1. Используйте перегрузку для Assert.Equal(), которая принимает аргумент IEqualityComparer<T>.
  2. Переопределить Equals() метод ReferenceType.
  3. Пропустите yield return и используйте коллекцию, которая реализует IEnumerable.

Возможно, первое решение является лучшим, поскольку оно не меняет реализацию GetEnumerable() или ReferenceType. В этом случае, когда GetEnumerable() используется только в тесте, я бы выбрал третий вариант, так как он самый простой. Это может выглядеть примерно так:

IEnumerable<ReferenceType> GetData()
{
    return new[] { new ReferenceType() };
}

или это:

IEnumerable<ReferenceType> GetData()
{
    var referenceTypes = new List<ReferenceType>();
    // ... add reference types
    return referenceTypes;
}

Это работает, так как теперь мы выполняем итерацию коллекции, которая была создана, когда мы получили перечисляемый объект, и не создаем новый экземпляр для каждой итерации.

0 голосов
/ 14 июня 2019

Я думаю, вы можете использовать функцию ниже для решения проблемы.

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;
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...