2011-03-04 136 views
20

问题 1次的出现(S):MSTest:CollectionAssert.AreEquivalent失败。预期集合包含

谁能告诉我为什么我的单元测试与此错误消息失败?

CollectionAssert.AreEquivalent failed。期望的收集包含1 发生(s)。实际的 集合包含0个事件。

目标

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

代码举例

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

[TestMethod] 
public void TestListOfT() 
{ 
    var list1 = new List<MyPerson>() 
    { 
     new MyPerson() 
     { 
      Name = "A", 
      Age = 20 
     }, 
     new MyPerson() 
     { 
      Name = "B", 
      Age = 30 
     } 
    }; 
    var list2 = new List<MyPerson>() 
    { 
     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; } 
} 

我也试过这条线(source

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

和这条线(source

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

附:

相关堆栈溢出的问题:

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

回答

21

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

+1

感谢您的回答!我会将你的答案标记为接受的答案,因为它解释了“为什么”。我会链接到我的答案显示[“如何”](http://stackoverflow.com/questions/5194966/mstest-collectionassert-areequivalent-failed-the-expected-collection-contains-1/5196791#5196791 )。 – Lernkurve 2011-03-06 13:25:20

+0

谢谢!我很感激! – neontapir 2011-03-07 03:46:24

+1

我从@Lernkurve的回答开始,它运作良好。之后,我尝试将方法Equals和GetHashCode移动到MyPerson类,使其实现IEqualityComparer 。我希望Assert.IsTrue(list1.SequenceEqual(list2));现在将在MyPerson上使用IEqualityComparer实现,但它不会。我得到“Assert.IsTrue失败”。所以,你的建议“......或者实现MyPerson.Equals()”似乎不起作用。我不懂为什么。 – 2013-03-05 15:50:13

19

它的工作原理,如果我添加一个IEqualityComparer<T>作为MSDN描述的,如果我使用Enumerable.SequenceEqual。但请注意,现在这些元素的顺序是相关的。

在单元测试

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

的IEqualityComparer

public class MyPersonEqualityComparer : IEqualityComparer<MyPerson> 
{ 
    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; 
    } 
} 
+4

为什么CollectionAssert.AreEquivalent失败?如果我想要使用AreEquivalent,因为订单不重要,该怎么办? – 2011-11-10 13:45:06

+1

为什么CollectionAssert.AreEquivalent(list1,list2);不工作,如果我在MyPerson上实现接口IEqualityComparer ?我试过了,但无法让它工作。 – 2013-03-05 15:54:42

+0

一个可能的解释是'CollectionAssert'可以使用它自己的语义来比较集合,而不是使用'IEqualityComparer '。看看你的单元测试框架的文档。您可以通过编写自己的'CollectionAssert.AreEqual'实现来确定这个问题,以查看比较器或测试框架方法是否存在问题。 – neontapir 2014-05-15 03:26:49

0

我写了这个测试的集合,其中顺序并不重要:

public static bool AreCollectionsEquivalent<T>(ICollection<T> collectionA, ICollection<T> collectionB, IEqualityComparer<T> 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<MyType>(collectionA, collectionB, comparer));

+0

而不是'!Any',你可以使用'All'。 – neontapir 2012-12-21 20:00:13

+1

如果项目的多样性是相关的,你的测试有一个错误。它将在“AreCollectionsEquivalent(新列表(){1,1,2}),新列表(){1,2,2},EqualityComparer .Default);” – 2013-03-06 09:03:24

+0

确实。我个人使用它来测试相当大和复杂的对象,所以这种情况从来都不是问题。 – Shaamaan 2013-03-06 10:03:35

0

用于测试由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<Contract> myContracts = new HashedSet<Contract>(); 

    public virtual Iesi.Collections.Generic.ISet<Contract> 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<EVProject>("C0G"); 

    CollectionAssert.AreEquivalent(TestData._evProjectLedgers.ToList(), evProject.EVProjectLedgers.ToList()); 

    tx.Commit(); 
} 

我使用的是nHibernate,它鼓励重写这些方法。我可以看到的一个缺点是我的Equals方法基于对象的业务关键,因此使用业务关键字和其他字段来测试相等性。你可以重写equals不过你想要的,但在这篇文章中提到的平等污染提防:

CollectionAssert.AreEquivalent failing... can't figure out why