CollectionAssert использовать с дженериками? - PullRequest
33 голосов
/ 14 марта 2010

Похоже, что CollectionAssert нельзя использовать с генериками. Это супер расстраивает; код, который я хочу проверить, использует дженерики. Что мне делать? Написать шаблон для преобразования между двумя? Вручную проверить эквивалентность коллекции?

Это не удалось:

ICollection<IDictionary<string, string>> expected = // ...

IEnumerable<IDictionary<string, string>> actual = // ...

// error 1 and 2 here
CollectionAssert.AreEqual(expected.GetEnumerator().ToList(), actual.ToList());

// error 3 here
Assert.IsTrue(expected.GetEnumerator().SequenceEquals(actual));

Ошибки компиляции:

Ошибка 1:

'System.Collections.Generic.IEnumerator>' не содержит определения для 'ToList' и не найден метод расширения 'ToList', принимающий первый аргумент типа 'System.Collections.Generic.IEnumerator>'

Ошибка 2

'System.Collections.Generic.IEnumerator>' не содержит определения для 'ToList' и не найден метод расширения 'ToList', принимающий первый аргумент типа 'System.Collections.Generic.IEnumerator>'

Ошибка 3

'System.Collections.Generic.IEnumerator>' не содержит определения для 'SequenceEquals' и не найден метод расширения 'SequenceEquals', принимающий первый аргумент типа 'System.Collections.Generic.IEnumerator>'

Что я делаю не так? Я правильно не использую расширения?

Обновление: Хорошо, это выглядит немного лучше, но все равно не работает:

IEnumerable<IDictionary<string, string>> expected = // ...

IEnumerable<IDictionary<string, string>> actual = // ...

CollectionAssert.AreEquivalent(expected.ToList(), actual.ToList()); // fails
CollectionAssert.IsSubsetOf(expected.ToList(), actual.ToList()); // fails

Я не хочу сравнивать списки; Меня волнует только равенство членов. Порядок членов не имеет значения. Как я могу обойти это?

Ответы [ 3 ]

35 голосов
/ 14 марта 2010

Вы можете использовать CollectionAssert с общими коллекциями. Хитрость заключается в том, чтобы понять, что методы CollectionAssert работают на ICollection, и хотя некоторые универсальные интерфейсы сбора данных реализуют ICollection, List<T> делает.

Таким образом, вы можете обойти это ограничение, используя метод расширения ToList:

IEnumerable<Foo> expected = //...
IEnumerable<Foo> actual = //...
CollectionAssert.AreEqual(expected.ToList(), actual.ToList());

Тем не менее, я все еще считаю, что CollectionAssert не работает во многих других отношениях, поэтому я склонен использовать Assert.IsTrue с методами расширения LINQ, например:

Assert.IsTrue(expected.SequenceEquals(actual));

FWIW, в настоящее время я использую эти методы расширения для выполнения других сравнений:

public static class EnumerableExtension
{
    public static bool IsEquivalentTo(this IEnumerable first, IEnumerable second)
    {
        var secondList = second.Cast<object>().ToList();
        foreach (var item in first)
        {
            var index = secondList.FindIndex(item.Equals);
            if (index < 0)
            {
                return false;
            }
            secondList.RemoveAt(index);
        }
        return secondList.Count == 0;
    }

    public static bool IsSubsetOf(this IEnumerable first, IEnumerable second)
    {
        var secondList = second.Cast<object>().ToList();
        foreach (var item in first)
        {
            var index = secondList.FindIndex(item.Equals);
            if (index < 0)
            {
                return false;
            }
            secondList.RemoveAt(index);
        }
        return true;
    }
}
5 голосов
/ 20 мая 2011

Если вы работаете с наборами, то используйте эту идиому

HashSet<string> set1  = new HashSet<string>(){"A","B"};
HashSet<string> set2  = new HashSet<string>(){"B","A"};

Assert.IsTrue(set1.SetEquals(set2));
1 голос
/ 14 марта 2010

Вы можете легко написать свою собственную универсальную версию, а затем переместить ее в базовый или служебный класс, который используется во всех ваших тестах. Основывайте его на операторах LINQ, таких как All и Any.

...