Использование CollectionAssert с дженериками?

Похоже, что 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

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


person Nick Heiner    schedule 14.03.2010    source источник
comment
Уверены ли вы? Он выдавал мне ошибки компилятора, которые я опубликую завтра утром.   -  person Nick Heiner    schedule 14.03.2010
comment
Я ошибался; CollectionAssert НЕ будет работать с ICollection‹T›. Работает только с ICollection. Это было запрошено в Connect, но пока не реализовано. Возможный обходной путь: stackoverflow.com/questions/662458/   -  person Mitch Wheat    schedule 14.03.2010
comment
Если я правильно помню, интерфейсы ICollection и ICollection‹T› СИЛЬНО отличаются. Это не случай IEnumerable по сравнению с IEnumerable‹T›. Пожалуйста, проверьте их методы. ICollection используется для чего-то ДРУГОГО, чем ICollection‹T›. ICollection даже не имеет метода ADD — он используется для более низкоуровневых целей, таких как многопоточность и маршаллинг. Поэтому я думаю, что вам лучше найти интерфейс, который будет лучше соответствовать вашим потребностям, может быть, простой IEnumerable?   -  person quetzalcoatl    schedule 09.03.2012
comment
Порядок членов неважен - именно для этого и нужен CollectionAssert.AreEquivalent. Какое сообщение об ошибке вы получаете при тестировании? (возможно, ваши ожидаемые и фактические не эквивалентны!)   -  person bacar    schedule 18.06.2012
comment
Это SequenceEqual, а не SequenceEquals, это, вероятно, ваша ошибка компиляции   -  person Diego C.    schedule 09.07.2012
comment
3 должен работать, это то, что я использую Assert.IsTrue(expected.SequenceEqual(actual));   -  person Ande    schedule 17.03.2015
comment
Microsoft уже открыла исходный код этой библиотеки? Можем ли мы сообщить и исправить это, чтобы CollectionAssert.AreEqual работало с большим количеством типов?   -  person Colonel Panic    schedule 15.05.2015


Ответы (3)


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

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

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

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

Assert.IsTrue(expected.SequenceEqual(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;
    }
}
person Mark Seemann    schedule 14.03.2010
comment
Вы должны импортировать пространство имен System.Linq в директиву using. ToList — это метод расширения. - person Mark Seemann; 14.03.2010
comment
Я добавил using System.Linq;, но все равно не работает: 'System.Collections.Generic.IEnumerator<System.Collections.Generic.IDictionary<string,string>>' does not contain a definition for 'ToList' and no extension method 'ToList' accepting a first argument of type 'System.Collections.Generic.IEnumerator<System.Collections.Generic.IDictionary<string,string>>' could be found - person Nick Heiner; 14.03.2010
comment
ToList не расширяет IEnumerator<T>, он расширяет IEnumerable<T>. Удалите вызов GetEnumerator(). - person Mark Seemann; 14.03.2010
comment
Верно-верно. Хорошо, но у меня все еще есть проблема, что это сравнение списков, но меня не волнует порядок объектов в коллекции. Я просто работаю с наборами. - person Nick Heiner; 14.03.2010
comment
Тогда это будет решаться с помощью CollectionAssert.AreEquivalent. - person Mark Seemann; 14.03.2010
comment
Это не для меня. (См. выше.) - person Nick Heiner; 14.03.2010
comment
SequenceEquals написан с ошибкой; должно быть SequenceEqual (без 's') - person an phu; 13.07.2015

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

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

Assert.IsTrue(set1.SetEquals(set2));
person Sudipta    schedule 20.05.2011

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

person John Saunders    schedule 14.03.2010