Is there an easy way in xunit.net to compare two collections without regarding the items' order?

烈酒焚心 提交于 2019-12-01 02:27:38

Brad Wilson from xunit.net told me in this Github Issue that one should use LINQ's OrderBy operator and afterwards Assert.Equal to verify that two collections contain equal items without regarding their order. Of course, you would have to have a property on the corresponding item class that you can use for ordering in the first place (which I didn't really have in my case).

Personally, I solved this problem by using FluentAssertions, a library that provides a lot of assertion methods that can be applied in a fluent style. Of course, there are also a lot of methods that you can use to validate collections.

In the context of my question, I would use something like the following code:

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

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

This test passes because the BeEquivalentTo call ignores the order of the items.

Shouldly is also a good alternative if you do not want to go with FluentAssertions.

Not a Xunit, but a Linq answer :

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

So in XUnit :

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

As @robi-y said, in Microsoft.VisualStudio.QualityTools.UnitTestFramework there is CollectionAssert.AreEquivalent

rducom

Maybe another way is:

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

This does checks the order too. This is what happens internally:

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;

So if you don't care about the order, just order both lists before:

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

You can use CollectionAssert.AreEquivalent from Microsoft

CollectionAssert.AreEquivalent(expected, actual);

This is almost the same as your code. The only simplification is using Assert.Contains instead of 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);
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!