CollectionAssert use with generics?
Solution 1
You can use CollectionAssert
with generic collections. The trick is to understand that the CollectionAssert
methods operate on ICollection
, and although few generic collection interfaces implement ICollection
, List<T>
does.
Thus, you can get around this limitation by using the ToList
extension method:
IEnumerable<Foo> expected = //...
IEnumerable<Foo> actual = //...
CollectionAssert.AreEqual(expected.ToList(), actual.ToList());
That said, I still consider CollectionAssert
broken in a lot of other ways, so I tend to use Assert.IsTrue(bool)
with the LINQ extension methods, like this:
Assert.IsTrue(expected.SequenceEqual(actual));
FWIW, I'm currently using these extension methods to perform other comparisons:
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;
}
}
Solution 2
If you are working with Sets, then use this Idiom
HashSet<string> set1 = new HashSet<string>(){"A","B"};
HashSet<string> set2 = new HashSet<string>(){"B","A"};
Assert.IsTrue(set1.SetEquals(set2));
Solution 3
You could easily write your own generic version, then move it to a base or utility class that's used in all of your tests. Base it on the LINQ operators like All and Any.
Nick Heiner
JS enthusiast by day, horse mask enthusiast by night. Talks I've Done
Updated on June 25, 2022Comments
-
Nick Heiner almost 2 years
It appears that
CollectionAssert
cannot be used with generics. This is super frustrating; the code I want to test does use generics. What am I to do? Write boilerplate to convert between the two? Manually check collection equivalence?This fails:
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));
Compiler errors:
Error 1:
'System.Collections.Generic.IEnumerator>' does not contain a definition for 'ToList' and no extension method 'ToList' accepting a first argument of type 'System.Collections.Generic.IEnumerator>' could be found
Error 2
'System.Collections.Generic.IEnumerator>' does not contain a definition for 'ToList' and no extension method 'ToList' accepting a first argument of type 'System.Collections.Generic.IEnumerator>' could be found
Error 3
'System.Collections.Generic.IEnumerator>' does not contain a definition for 'SequenceEquals' and no extension method 'SequenceEquals' accepting a first argument of type 'System.Collections.Generic.IEnumerator>' could be found
What am I doing wrong? Am I not using extensions correctly?
Update: Ok, this looks a bit better, but still doesn't work:
IEnumerable<IDictionary<string, string>> expected = // ... IEnumerable<IDictionary<string, string>> actual = // ... CollectionAssert.AreEquivalent(expected.ToList(), actual.ToList()); // fails CollectionAssert.IsSubsetOf(expected.ToList(), actual.ToList()); // fails
I don't want to be comparing lists; I only care about set membership equality. The order of the members is unimportant. How can I get around this?
-
Mark Seemann about 14 yearsYou have to import the System.Linq namespace in a using directive.
ToList
is an extension method. -
Nick Heiner about 14 yearsI added
using System.Linq;
but it still doesn't work:'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
-
Mark Seemann about 14 years
ToList
doesn't extendIEnumerator<T>
, it extendsIEnumerable<T>
. Remove the call toGetEnumerator()
. -
Nick Heiner about 14 yearsRight right. Ok, but I still have the problem that this is comparing lists, but I don't care about the order of objects in the collection. I'm just working with sets.
-
Mark Seemann about 14 yearsThat would be addressed by CollectionAssert.AreEquivalent, then.
-
Nick Heiner about 14 yearsThat fails for me. (See above.)
-
an phu almost 9 yearsSequenceEquals is misspelled; should be SequenceEqual (without the 's')