比较两个列表中的对象在C#单元测试

问题描述:

我想创建一个单元测试,比较两个字符串数组列表。比较两个列表中的<string[]>对象在C#单元测试

我试图创建两个完全相同的List<string[]>的对象,但是当我使用CollectionAssert.AreEqual(expected, actual);,该测试失败:

[TestMethod] 
public void TestList() 
{ 
    List<string[]> expected = new List<string[]> { 
     new string[] { "John", "Smith", "200" }, 
     new string[] { "John", "Doe", "-100" } 
    }; 

    List<string[]> actual = new List<string[]> { 
     new string[] { "John", "Smith", "200" }, 
     new string[] { "John", "Doe", "-100" } 
    }; 

    CollectionAssert.AreEqual(expected, actual); 
} 

我也试过Assert.IsTrue(expected.SequenceEqual(actual));,但失败也是如此。

如果我比较两个字符串列表或两个字符串数组,但它们在比较两个字符串数组列表时无效。

我假设这些方法失败,因为他们比较两个对象引用列表而不是数组字符串值。

如何比较两个List<string[]>对象并判断它们是否真的相同?

+2

试试这个:元素,你可以当你把它做到这一点通过在IComparer'expected.Zip(实际,(E,A)=> e.SequenceEqual(一))所有( x => x)'。 – Enigmativity

+0

出于好奇......如果它们具有相同的元素但顺序不同,您会认为列表“相等”吗?另外,值得注意的是,一个字符串数组是一个对象的可怕替代品。 – David

+0

@David对于这个特定的测试,我会很好的解决方案,要求元素的顺序相同,以及忽略顺序的解决方案。我同意对象通常比字符串数组更好。此代码是更大图片的一部分,需要采用此格式。 –

这是失败,因为在清单中的项目是对象(string[]),并因为你没有指定如何CollectionAssert.AreEqual应该比较它回落到是比较引用的默认行为的两个序列的元素。如果你要改变你的名单如下,例如,你会发现,测试通过,因为现在这两个列表都引用同一个数组:

var first = new string[] { "John", "Smith", "200" }; 
var second = new string[] { "John", "Smith", "200" }; 

List<string[]> expected = new List<string[]> { first, second}; 
List<string[]> actual = new List<string[]> { first, second}; 

以避免破坏参照比较,你需要告诉CollectionAssert.AreEqual如何比较

CollectionAssert.AreEqual(expected, actual, StructuralComparisons.StructuralComparer); 

CollectionAssert.AreEqual(expected, actual);失败,因为它比较对象引用。 expectedactual指的是不同的对象。

Assert.IsTrue(expected.SequenceEqual(actual));因相同原因失败。这一次的内容expectedactual进行了比较,但元素本身是不同的数组引用。

也许尝试使用SelectMany拉平两个序列:

var expectedSequence = expected.SelectMany(x => x).ToList(); 
var actualSequence = actual.SelectMany(x => x).ToList(); 
CollectionAssert.AreEqual(expectedSequence, actualSequence); 

由于Enigmativity在他的评论正确地注意到,的SelectMany可以给予了积极的结果,当阵列数量和/或它们的元素是不同的,但展平列表将导致相同数量的元素。只有在这些阵列中始终具有相同数量的数组和元素的情况下才是安全的。

+0

你已经钉了它,与对象引用的解释,但'.SelectMany'方法创建了一大堆“误报”,并且不需要'.Select(y => y)' – Enigmativity

+0

感谢评论。我错过了。我编辑了我的帖子。 – Kapol

最好的解决方案是检查每个子集合中的项目以及每个子集合中项目的数量。

试试这个:

bool equals = expected.Count == actual.Count && 
       Enumerable.Range(0, expected.Count).All(i => expected[i].Length == actual[i].Length && 
                  expected[i].SequenceEqual(actual[i])); 
Assert.IsTrue(equals); 

这将检查:

  • 两个列表具有相同的长度
  • 所有都列出了一子集的具有相同的长度
  • 每副子集中的物品都是一样的

注意:使用SelectMany不是一个好主意,因为它可能会产生误报,您在第二个列表中有相同的项目,但分散在不同的子集合中。我的意思是,即使第二个在一个子集合中有相同的项目,它也会考虑两个列表是相同的。