Есть ли простой способ в 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)
в приведенном выше коде.
Спасибо за ваши ответы заранее.
Ответы
Ответ 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);
}