web-dev-qa-db-ja.com

xunit.netで、アイテムの順序を考慮せずに2つのコレクションを比較する簡単な方法はありますか?

テストの1つで、コレクションに特定のアイテムがあることを確認します。したがって、私はこのコレクションを予想されるコレクションのアイテムと比較したいと思いますアイテムの順序には関係ありません。現在、私のテストコードは次のようになります。

_[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)ステートメントは削除されません。

よろしくお願いします。

20
feO2x

Xunit.netのBrad Wilsonがこれについて教えてくれました Github Issue LINQのOrderBy演算子を使用し、その後Assert.Equal 2つのコレクションに順序に関係なく等しいアイテムが含まれていることを確認します。もちろん、最初に注文に使用できる対応する項目クラスのプロパティが必要になります(私の場合は実際にはありませんでした)。

個人的に、私はこの問題を、流れるようなスタイルで適用できる多くのアサーションメソッドを提供するライブラリである FluentAssertions を使用して解決しました。もちろん コレクションの検証に使用できるメソッドも多数あります

私の質問のコンテキストでは、次のコードのようなものを使用します:

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

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

BeEquivalentTo呼び出しがアイテムの順序を無視するため、このテストは合格です。

Shouldly は、FluentAssertionsを使いたくない場合の良い選択肢でもあります。

21
feO2x

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

11
rducom

多分別の方法は:

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

Microsoft からCollectionAssert.AreEquivalentを使用できます

CollectionAssert.AreEquivalent(expected, actual);
1
mantale

これは、コードとほとんど同じです。唯一の単純化は、Assert.True(expected.Contains(...))の代わりにAssert.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);
}
0
Alex Jorgenson