MSTest: CollectionAssert.AreEquivalent не удалось.Ожидаемая коллекция содержит 1 вхождение - PullRequest
22 голосов
/ 04 марта 2011

Вопрос :

Может кто-нибудь сказать мне, почему мой модульный тест не проходит с этим сообщением об ошибке?

CollectionAssert.AreEquivalent не удалось.Ожидаемая коллекция содержит 1 случай (ы) из.Фактическая коллекция содержит 0 экземпляров.

Цель :

Я хотел бы проверить, идентичны ли два списка.Они идентичны, если оба содержат одинаковые элементы с одинаковыми значениями свойств.Порядок не имеет значения.

Пример кода :

Это код, который выдает ошибку.list1 и list2 идентичны, то есть копируют друг друга.

[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());

и эта строка ( источник )

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

PS

Вопросы, связанные с переполнением стека:

Я видел оба этих вопроса,но ответы не помогли.

Ответы [ 5 ]

22 голосов
/ 04 марта 2011

Вы абсолютно правы.Если вы не предоставите что-то вроде IEqualityComparer<MyPerson> или реализуете MyPerson.Equals(), два объекта MyPerson будут сравниваться с object.Equals, как и любой другой объект.Поскольку объекты различны, Assert не будет выполнен.

21 голосов
/ 04 марта 2011

Это работает, если я добавлю 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 голосов
/ 15 августа 2013

Я получал эту же ошибку при тестировании коллекции, сохраненной с помощью 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 fail ... не могу понять, почему

0 голосов
/ 08 января 2019

Если вы хотите достичь этого без написания comaparer равенства, вы можете использовать библиотеку модульного тестирования, которая называется FluentAssertions ,

https://fluentassertions.com/documentation/

Он имеет множество встроенных функций расширения равенства, в том числе и для Коллекций. Вы можете установить его через Nuget, и он действительно прост в использовании.

Если взять пример из приведенного выше вопроса, то в конце вы должны написать

list1.Should().BeEquivalentTo(list2);

По умолчанию порядок имеет значение в двух коллекциях, однако его также можно изменить.

0 голосов
/ 08 октября 2012

Я написал это для тестирования коллекций, где порядок не важен:

    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));

...