C# Assert.AreEqual 如何确定两个通用 IEnumerables 之间的相等性?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/933285/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How does Assert.AreEqual determine equality between two generic IEnumerables?
提问by Jason Baker
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:
我有一个单元测试来检查一个方法是否返回正确的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;
}
}
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...
如果我将此方法的结果存储在 中actual
,则创建另一个 enumerable expected
,并像这样比较它们......
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:
我为此编写了一个IEnumerable
类似于Pythonzip
函数的扩展方法(它将两个 IEnumerables 组合成一组对)并尝试了这个:
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?
有效!那么这两个Assert.AreEqual
s有什么区别呢?
采纳答案by jrista
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 two IEnumerable
s, which is a valid comparison...but not what you needed. You needed to compare what the two IEnumerable
s were intended to enumerate.
Assert.AreEqual
将比较手头的两个对象。IEnumerable
s 本身就是类型,并提供一种机制来迭代某些集合……但它们实际上不是那个集合。您的原始比较比较了两个IEnumerable
s,这是一个有效的比较……但不是您需要的。您需要比较两个IEnumerable
s 打算枚举的内容。
Here is how I compare two enumerables:
这是我比较两个可枚举的方法:
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);
}
I am not sure whether the above is less code than your .Zip
method, but it is about as simple as it gets.
我不确定上面的代码是否比你的.Zip
方法少,但它很简单。
回答by Jason Baker
Found it:
找到了:
Assert.IsTrue(expected.SequenceEqual(actual));
回答by jerryjvl
Have you considered using the CollectionAssert
class instead...considering that it is intended to perform equality checks on collections?
您是否考虑过使用CollectionAssert
该类......考虑到它旨在对集合执行相等性检查?
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?
附录:
如果被比较的“集合”是枚举,那么简单地用“ new List<T>(enumeration)
”包装它们是执行比较的最简单方法。构建一个新列表当然会导致一些开销,但在单元测试的上下文中,我希望这应该无关紧要吗?
回答by bacar
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:
我认为断言你想要的平等的最简单和最清晰的方法是结合 jerryjvl 的答案和 MEMark 对他的帖子的评论 - 结合CollectionAssert.AreEqual
扩展方法:
CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());
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:
这提供了比 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.
You'll be reallypleased 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? ;-)
如果/当你的测试失败时,你会很高兴你这样做 - 有时你甚至可以知道出了什么问题而不必打破调试器 - 嘿,你做的 TDD 是正确的,所以你首先编写一个失败的测试,对?;-)
The error messages get even more helpful if you're using AreEquivalent
to test for equivalence (order doesn't matter):
如果您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).