I have a unit test to check whether a method returns the correct IEnumerable
. The method builds the enumerable using yield return
. The class that it is an enumerable of is below:
enum TokenType
{
NUMBER,
COMMAND,
ARITHMETIC,
}
internal class Token
{
public TokenType type { get; set; }
public string text { get; set; }
public static bool operator == (Token lh, Token rh) { return (lh.type == rh.type) && (lh.text == rh.text); }
public static bool operator != (Token lh, Token rh) { return !(lh == rh); }
public override int GetHashCode()
{
return text.GetHashCode() % type.GetHashCode();
}
public override bool Equals(object obj)
{
return this == (Token)obj;
}
}
This is the relevant part of the method:
foreach (var lookup in REGEX_MAPPING)
{
if (lookup.re.IsMatch(s))
{
yield return new Token { type = lookup.type, text = s };
break;
}
}
If I store the result of this method in actual
, make another enumerable expected
, and compare them like this...
Assert.AreEqual(expected, actual);
..., the assertion fails.
I wrote an extension method for IEnumerable
that is similar to Python's zip
function (it combines two IEnumerables into a set of pairs) and tried this:
foreach(Token[] t in expected.zip(actual))
{
Assert.AreEqual(t[0], t[1]);
}
It worked! So what is the difference between these two Assert.AreEqual
s?
Have you considered using the
CollectionAssert
class instead...considering that it is intended to perform equality checks on collections?Addendum:
If the 'collections' being compared are enumerations, then simply wrapping them with '
new List<T>(enumeration)
' is the easiest way to perform the comparison. Constructing a new list causes some overhead of course, but in the context of a unit test this should not matter too much I hope?I think the simplest and clearest way to assert the equality you want is a combination of the answer by jerryjvl and comment on his post by MEMark - combine
CollectionAssert.AreEqual
with extension methods:This gives richer error information than the SequenceEqual answer suggested by the OP (it will tell you which element was found that was unexpected). For example:
You'll be really pleased you did it this way if/when your test fails - sometimes you can even know what's wrong without having to break out the debugger - and hey you're doing TDD right, so you write a failing test first, right? ;-)
The error messages get even more helpful if you're using
AreEquivalent
to test for equivalence (order doesn't matter):Assert.AreEqual
is going to compare the two objects at hand.IEnumerable
s are types in and of themselves, and provide a mechanism to iterate over some collection...but they are not actually that collection. Your original comparison compared twoIEnumerable
s, which is a valid comparison...but not what you needed. You needed to compare what the twoIEnumerable
s were intended to enumerate.Here is how I compare two enumerables:
I am not sure whether the above is less code than your
.Zip
method, but it is about as simple as it gets.Found it: