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

Есть ли простой способ в xunit.net сравнить две коллекции без учета заказа предметов?

В одном из моих тестов я хочу убедиться, что в коллекции есть определенные элементы. Поэтому я хочу сравнить эту коллекцию с элементами ожидаемой коллекции , не относящейся к порядку элементов. В настоящее время мой тестовый код выглядит примерно так:

[Fact]
public void SomeTest()
{
    // Do something in Arrange and Act phase to obtain a collection
    List<int> actual = ...

    // Now the important stuff in the Assert phase
    var expected = new List<int> { 42, 87, 30 };
    Assert.Equal(expected.Count, actual.Count);
    foreach (var item in actual)
        Assert.True(expected.Contains(item));
}

Есть ли более простой способ добиться этого на xunit.net? Я не могу использовать Assert.Equal, так как этот метод проверяет, является ли порядок элементов одинаковым в обеих коллекциях. Я посмотрел на Assert.Collection, но это не удаляет оператор Assert.Equal(expected.Count, actual.Count) в приведенном выше коде.

Спасибо за ваши ответы заранее.

4b9b3361

Ответ 1

Брэд Уилсон из xunit.net сказал мне в этом Github Issue, что нужно использовать оператор LINQ OrderBy, а затем Assert.Equal, чтобы убедиться, что две коллекции содержат равные предметов без учета их заказа. Конечно, вы должны иметь свойство в соответствующем классе элементов, которое вы можете использовать для упорядочения в первую очередь (чего у меня в действительности не было).

Лично я решил эту проблему, используя FluentAssertions, библиотеку, которая предоставляет множество методов утверждения, которые могут быть применены в свободном стиле. Конечно, существует множество методов, которые можно использовать для проверки коллекций.

В контексте моего вопроса я бы использовал что-то вроде следующего кода:

[Fact]
public void Foo()
{
    var first = new[] { 1, 2, 3 };
    var second = new[] { 3, 2, 1 };

    first.Should().BeEquivalentTo(second);
}

Этот тест проходит, потому что вызов BeEquivalentTo игнорирует порядок элементов.

Shouldly также является хорошей альтернативой, если вы не хотите идти с FluentAssertions.

Ответ 2

Не Xunit, а ответ Linq:

bool areSame = !expected.Except(actual).Any() && expected.Count == actual.Count;

Итак, в XUnit:

Assert.True(!expected.Except(actual).Any() && expected.Count == actual.Count));

Как сказал @robi-y, в Microsoft.VisualStudio.QualityTools.UnitTestFramework есть CollectionAssert.AreEquivalent

Ответ 3

Может быть, другой способ:

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

Это тоже проверяет порядок. Это то, что происходит внутри:

using (IEnumerator<TSource> e1 = first.GetEnumerator())
using (IEnumerator<TSource> e2 = second.GetEnumerator())
{
    while (e1.MoveNext())
    {
        if (!(e2.MoveNext() && comparer.Equals(e1.Current, e2.Current))) return false;
    }
    if (e2.MoveNext()) return false;
}
return true;

Так что если вы не заботитесь о порядке, просто закажите оба списка раньше:

Assert.True(expected.OrderBy(i => i).SequenceEqual(actual.OrderBy(i => i)));

Ответ 4

Вы можете использовать CollectionAssert.AreEquivalent из Microsoft

CollectionAssert.AreEquivalent(expected, actual);

Ответ 5

Это почти так же, как ваш код. Единственное упрощение - использование Assert.Contains вместо Assert.True(expected.Contains(...)).

[Fact]
public void SomeTest()
{
    // Do something in Arrange and Act phase to obtain a collection
    List<int> actual = ...

    // Now the important stuff in the Assert phase
    var expected = new List<int> { 42, 87, 30 };
    Assert.Equal(expected.Count, actual.Count);
    foreach (var item in expected)
        Assert.Contains(item, actual);
}