问题
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?
回答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;
}
}
回答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));
回答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.
来源:https://stackoverflow.com/questions/2441188/collectionassert-use-with-generics