如何在单元测试中比较列表

225

这个测试怎么会失败呢?

[TestMethod]
public void Get_Code()
{
    var expected = new List<int>();
    expected.AddRange(new [] { 100, 400, 200, 900, 2300, 1900 });

    var actual = new List<int>();
    actual.AddRange(new [] { 100, 400, 200, 900, 2300, 1900 });

    Assert.AreEqual(expected, actual);
    // Assert.AreSame(expected, actual)       fails
    // Assert.IsTrue(expected.Equals(actual)) fails
}
7个回答

455
为了对集合进行断言,应该使用 CollectionAssert
CollectionAssert.AreEqual(expected, actual);

List<T> 没有覆盖 Equals 方法,因此如果 Assert.AreEqual 只是调用 Equals 方法,它最终将使用引用相等性。


9
我希望在操作失败时能够得到更详细的提示信息。"不同数量的元素"和"索引为0的元素不匹配"这些提示实际上并没有什么用。那它们到底是什么意思呢? - Colonel Panic
49
如果您不关心项目的顺序:{A,B,C} == {C,B,A},那么请改用 CollectionAssert.AreEquivalent 来进行验证。详情请参考 https://msdn.microsoft.com/en-us/library/ms243779.aspx - user2023861
3
请注意,CollectionAssert.AreEqual 的速度可能比 Assert.IsTrue...SequenceEqual 慢得多。 - Mark Sowul
2
@MarkSowul:但它带来了更好的故障诊断,对吧? - Jon Skeet
3
嗯...听起来值得报告为一个 bug。没有理由会那么糟糕。 - Jon Skeet
显示剩余4条评论

47

我想这会有所帮助

Assert.IsTrue(expected.SequenceEqual(actual));

4
我也曾经这样做,但我希望CollectionAssert能够提供更有帮助的失败信息。 - Jon Skeet
4
很遗憾,它并没有通过测试:"CollectionAssert.AreEqual 失败。(索引为0的元素不匹配。)" (这些元素是什么?) - namey
对于我的包含300k元素的字节数组,它比CollectionAsser.AreEqual快两倍。 - juwens

23

如果你想检查每个对象是否包含相同的值集合,那么你应该使用:

CollectionAssert.AreEquivalent(expected, actual);

编辑:

"如果两个集合拥有相同数量的相同元素,但顺序不同,则它们是等效的。 元素相等意味着它们的值相等,而不是指它们引用相同对象。" - https://msdn.microsoft.com/en-us/library/ms243779.aspx


19

我尝试了本主题中的其他答案,但它们对我没有用。我正在比较具有相同属性值存储的对象集合,但这些对象是不同的。

方法调用:

CompareIEnumerable(to, emailDeserialized.ToIndividual,
            (x, y) => x.ToName == y.ToName && x.ToEmailAddress == y.ToEmailAddress);

比较的方法:

private static void CompareIEnumerable<T>(IEnumerable<T> one, IEnumerable<T> two, Func<T, T, bool> comparisonFunction)
    {
        var oneArray = one as T[] ?? one.ToArray();
        var twoArray = two as T[] ?? two.ToArray();

        if (oneArray.Length != twoArray.Length)
        {
            Assert.Fail("Collections are not same length");
        }

        for (int i = 0; i < oneArray.Length; i++)
        {
            var isEqual = comparisonFunction(oneArray[i], twoArray[i]);
            Assert.IsTrue(isEqual);
        }
    }

3
不错的补充,或者你也可以覆盖Equals方法,这样CollectionAssert也能正常工作。 - Ray Cheng

7

这个测试比较了一个日期输入,检查它是否为闰年,如果是,则从输入的日期输出20个闰年,如果不是,则输出接下来的20个闰年。myTest.Testing指的是myTest实例,该实例从包含所需计算值的名为Testing的列表中调用值。这是我必须完成的练习的一部分。

[TestMethod]
        public void TestMethod1()
        {
            int testVal = 2012;
            TestClass myTest = new TestClass();
            var expected = new List<int>();
            expected.Add(2012);
            expected.Add(2016);
            expected.Add(2020);
            expected.Add(2024);
            expected.Add(2028);
            expected.Add(2032);
            expected.Add(2036);
            expected.Add(2040);
            expected.Add(2044);
            expected.Add(2048);
            expected.Add(2052);
            expected.Add(2056);
            expected.Add(2060);
            expected.Add(2064);
            expected.Add(2068);
            expected.Add(2072);
            expected.Add(2076);
            expected.Add(2080);
            expected.Add(2084);
            expected.Add(2088);
            var actual = myTest.Testing(2012);
            CollectionAssert.AreEqual(expected, actual);
        }

5

流畅的断言可对数组进行深度比较:

actualArray.Should().BeEquivalentTo(expectedArray)

其他答案对我都没有用,尽管通过调试我可以看到我的列表是相等的。这个答案的变体起作用了:actual.ShouldDeepEqual(expected); - MJ Hughes

0
List<AdminUser> adminDetailsExpected = new List<AdminUser>()
{
new AdminUser  {firstName = "test1" , lastName = "test1" , userId = 
"001test1"  },
new AdminUser {firstName = "test2" , lastName = "test2" , userId = 
"002test2"   }
};

//操作

List<AdminUser> adminDetailsActual = RetrieveAdmin(); // your retrieve logic goes here

//断言

Assert.AreEqual(adminDetailsExpected.Count, adminDetailsActual.Count);  //Test succeeds if the count matches else fails. This count can be used as a work around to test

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接