Подтвердить что ты не робот

MSTest: CollectionAssert.AreEquivalent не удалось. Ожидаемая коллекция содержит 1 случай (ы)

Вопрос

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

CollectionAssert.AreEquivalent не удалось. Ожидаемая коллекция содержит 1     появление (s) of. Настоящий     коллекция содержит 0 появление (s).

Цель

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

Пример кода:

Это код, который вызывает ошибку. 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; }
}

Я также пробовал эту строку (источник)

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

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

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

P.S.

Связанные вопросы:

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

4b9b3361

Ответ 1

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

Ответ 2

Он работает, если я добавляю IEqualityComparer<T>, как описано в MSDN, и если я использую Enumerable.SequenceEqual. Обратите внимание, однако, что теперь порядок элементов имеет значение.

В unit test

//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;
    }
}

Ответ 3

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

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

Ответ 4

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