MSTest:CollectionAssert.AreEquivalent失败。 预期的集合包含1次出现

问题

任何人都可以告诉我为什么我的unit testing失败了这个错误消息?

CollectionAssert.AreEquivalent失败。 预期的集合包含1次出现。 实际集合包含0次出现。

目标

我想检查两个列表是否相同。 如果它们包含具有相同属性值的相同元素,则它们是相同的。 订单无关紧要。

代码示例

这是产生错误的代码。 list1list2是相同的,即彼此的复制粘贴。

 [TestMethod] public void TestListOfT() { var list1 = new List() { new MyPerson() { Name = "A", Age = 20 }, new MyPerson() { Name = "B", Age = 30 } }; var list2 = new List() { new MyPerson() { Name = "A", Age = 20 }, new MyPerson() { Name = "B", Age = 30 } }; CollectionAssert.AreEquivalent(list1.ToList(), list2.ToList()); } public class MyPerson { public string Name { get; set; } public int Age { get; set; } } 

我也试过这一行( 来源 )

 CollectionAssert.AreEquivalent(list1.ToList(), list2.ToList()); 

这条线( 来源 )

 CollectionAssert.AreEquivalent(list1.ToArray(), list2.ToArray()); 

PS

相关Stack Overflow问题:

我已经看到了这两个问题,但答案没有帮助。

  • CollectionAssert与generics一起使用?
  • 使用CollectionAssert对IList进行unit testing

你是绝对正确的。 除非你提供类似IEqualityComparer或实现MyPerson.Equals()东西,否则两个MyPerson对象将与MyPerson进行比较,就像任何其他对象一样。 由于对象不同,Assert将失败。

如果我按照MSDN上的描述添加IEqualityComparer并且使用Enumerable.SequenceEqual它就可以工作。 但请注意,现在元素的顺序是相关的。

在unit testing中

 //CollectionAssert.AreEquivalent(list1, list2); // Does not work Assert.IsTrue(list1.SequenceEqual(list2, new MyPersonEqualityComparer())); // Works 

的IEqualityComparer

 public class MyPersonEqualityComparer : IEqualityComparer { public bool Equals(MyPerson x, MyPerson y) { if (object.ReferenceEquals(x, y)) return true; if (object.ReferenceEquals(x, null) || object.ReferenceEquals(y, null)) return false; return x.Name == y.Name && x.Age == y.Age; } public int GetHashCode(MyPerson obj) { if (object.ReferenceEquals(obj, null)) return 0; int hashCodeName = obj.Name == null ? 0 : obj.Name.GetHashCode(); int hasCodeAge = obj.Age.GetHashCode(); return hashCodeName ^ hasCodeAge; } } 

在测试nHibernate持久化的集合时,我遇到了同样的错误。 我能够通过覆盖Equals和GetHashCode方法来实现这一点。 如果我没有覆盖两者,我仍然会遇到你提到的同样的错误:

 CollectionAssert.AreEquivalent failed. The expected collection contains 1 occurrence(s) of . The actual collection contains 0 occurrence(s). 

我有以下对象:

 public class EVProjectLedger { public virtual long Id { get; protected set; } public virtual string ProjId { get; set; } public virtual string Ledger { get; set; } public virtual AccountRule AccountRule { get; set; } public virtual int AccountLength { get; set; } public virtual string AccountSubstrMethod { get; set; } private Iesi.Collections.Generic.ISet myContracts = new HashedSet(); public virtual Iesi.Collections.Generic.ISet Contracts { get { return myContracts; } set { myContracts = value; } } public override bool Equals(object obj) { EVProjectLedger evProjectLedger = (EVProjectLedger)obj; return ProjId == evProjectLedger.ProjId && Ledger == evProjectLedger.Ledger; } public override int GetHashCode() { return new { ProjId, Ledger }.GetHashCode(); } } 

我使用以下方法测试过:

 using (ITransaction tx = session.BeginTransaction()) { var evProject = session.Get("C0G"); CollectionAssert.AreEquivalent(TestData._evProjectLedgers.ToList(), evProject.EVProjectLedgers.ToList()); tx.Commit(); } 

我正在使用nHibernate,它鼓励覆盖这些方法。 我可以看到的一个缺点是我的Equals方法基于对象的业务键,因此使用业务键而不是其他字段测试相等性。 您可以根据需要覆盖Equals,但要注意本文中提到的平等污染:

CollectionAssert.AreEquivalent失败……无法弄清楚原因

我写这个来测试订单不重要的集合:

  public static bool AreCollectionsEquivalent(ICollection collectionA, ICollection collectionB, IEqualityComparer comparer) { if (collectionA.Count != collectionB.Count) return false; foreach (var a in collectionA) { if (!collectionB.Any(b => comparer.Equals(a, b))) return false; } return true; } 

不像使用SequenceEquals那样优雅,但它可以工作。

当然要使用它你只需:

Assert.IsTrue(AreCollectionsEquivalent(collectionA, collectionB, comparer));