我有一个单元测试来检查方法是否返回正确的IEnumerable
。该方法使用yield return
构建可枚举。它是可枚举的类如下:
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;
}
}
这是该方法的相关部分:
foreach (var lookup in REGEX_MAPPING)
{
if (lookup.re.IsMatch(s))
{
yield return new Token { type = lookup.type, text = s };
break;
}
}
如果我将此方法的结果存储在actual
中,请创建另一个可枚举的expected
,并将它们比作这样......
Assert.AreEqual(expected, actual);
...,断言失败。
我为IEnumerable
编写了一个类似于Python's zip
function的扩展方法(它将两个IEnumerables组合成一组对)并尝试了这个:
foreach(Token[] t in expected.zip(actual))
{
Assert.AreEqual(t[0], t[1]);
}
有效!那么这两个Assert.AreEqual
之间的区别是什么?
答案 0 :(得分:88)
找到它:
Assert.IsTrue(expected.SequenceEqual(actual));
答案 1 :(得分:48)
您是否考虑过使用CollectionAssert
类...考虑到它是否打算对集合执行相等检查?
<强>附录:强>
如果要比较的“集合”是枚举,那么简单地用“new List<T>(enumeration)
”包装它们是执行比较的最简单方法。构建一个新列表当然会产生一些开销,但是在单元测试的背景下,我希望这不应该太重要吗?
答案 2 :(得分:25)
Assert.AreEqual
将比较手头的两个对象。 IEnumerable
s本身就是类型,并提供迭代某些集合的机制......但它们实际上并不是那个集合。您的原始比较比较了两个IEnumerable
s,这是一个有效的比较...但不是您需要的。您需要比较两个IEnumerable
要枚举的内容。
以下是我比较两个枚举的方法:
Assert.AreEqual(t1.Count(), t2.Count());
IEnumerator<Token> e1 = t1.GetEnumerator();
IEnumerator<Token> e2 = t2.GetEnumerator();
while (e1.MoveNext() && e2.MoveNext())
{
Assert.AreEqual(e1.Current, e2.Current);
}
我不确定上面的代码是否比你的.Zip
方法少,但它就像它得到的一样简单。
答案 3 :(得分:19)
我认为断言你想要的平等最简单,最清晰的方法是结合jerryjvl的回答和MEMark评论他的帖子 - 将CollectionAssert.AreEqual
与扩展方法结合起来:
CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());
这提供了比OP建议的SequenceEqual答案更丰富的错误信息(它将告诉您发现哪个元素是意外的)。例如:
IEnumerable<string> expected = new List<string> { "a", "b" };
IEnumerable<string> actual = new List<string> { "a", "c" }; // mismatching second element
CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());
// Helpful failure message!
// CollectionAssert.AreEqual failed. (Element at index 1 do not match.)
Assert.IsTrue(expected.SequenceEqual(actual));
// Mediocre failure message:
// Assert.IsTrue failed.
如果/当你的测试失败时,你真的非常高兴你这样做了 - 有时你甚至可以知道什么是错的而不必打破调试器 - 而且你正在做TDD是的,所以你先写一个失败的测试,对吧? ; - )
如果您使用AreEquivalent
来测试等效性(顺序无关紧要),则错误消息会更有帮助:
CollectionAssert.AreEquivalent(expected.ToList(), actual.ToList());
// really helpful error message!
// CollectionAssert.AreEquivalent failed. The expected collection contains 1
// occurrence(s) of <b>. The actual collection contains 0 occurrence(s).