44

[Theory]一緒に使用すると[InlineData]、提供されたインライン データの各項目に対してテストが作成されます。ただし、使用[MemberData]すると、1 つのテストとして表示されます。

[MemberData]テストを複数のテストとして表示する方法はありますか?

4

5 に答える 5

39

私は自分のプロジェクトでこれを理解しようと多くの時間を費やしました。@NPadrutt 自身によるこの関連する Github の議論は大いに役立ちましたが、それでも混乱を招きました。

tl;dr は次のとおりです。各テストに提供されたオブジェクトが実装によって完全にシリアル化および逆シリアル[MemberInfo]化されない限り、単一のグループ テストが報告されます。IXunitSerializable


バックグラウンド

私自身のテスト設定は次のようなものでした:

public static IEnumerable<object[]> GetClients()
{
    yield return new object[] { new Impl.Client("clientType1") };
    yield return new object[] { new Impl.Client("clientType2") };
}

[Theory]
[MemberData(nameof(GetClients))]
public void ClientTheory(Impl.Client testClient)
{
    // ... test here
}

テストは、予想どおり、 の各オブジェクトに対して 1 回ずつ、合計 2 回実行[MemberData]されました。@NPadrutt が経験したように、テスト エクスプローラーには 2 つではなく 1 つの項目しか表示されませんでした。これは、提供されたオブジェクトImpl.Clientが、xUnit がサポートするいずれのインターフェースによってもシリアライズ可能でなかったためです (これについては後で詳しく説明します)。

私の場合、メイン コードにテストの懸念事項を持ち込みたくありませんでした。実際のクラスの周りにシン プロキシを記述して、xUnit ランナーをだましてシリアル化できると思わせることができると思っていましたが、認めるよりも長い間それと格闘した後、理解していない部分が:

オブジェクトは、順列をカウントするために検出中にシリアル化されるだけではありません。各オブジェクトは、テストの開始時にテスト実行時に逆シリアル化されます。

したがって、提供するすべてのオブジェクトは[MemberData]、完全な往復 (逆) シリアル化をサポートする必要があります。これは今では明らかなように思えますが、理解しようとしている間、それに関するドキュメントを見つけることができませんでした.


解決

  • すべてのオブジェクト (およびそれに含まれる可能性のある非プリミティブ) を完全にシリアライズおよびデシリアライズできることを確認してください。xUnit を実装IXunitSerializableすると、xUnit はシリアライズ可能なオブジェクトであることがわかります。

  • 私の場合のように、メイン コードに属性を追加したくない場合、1 つの解決策は、実際のクラスを再作成するために必要なすべてを表すことができる、テスト用の薄いシリアル化可能なビルダー クラスを作成することです。動作させた後の上記のコードは次のとおりです。

TestClientBuilder

public class TestClientBuilder : IXunitSerializable
{
    private string type;

    // required for deserializer
    public TestClientBuilder()
    {
    }

    public TestClientBuilder(string type)
    {
        this.type = type;
    }

    public Impl.Client Build()
    {
        return new Impl.Client(type);
    }

    public void Deserialize(IXunitSerializationInfo info)
    {
        type = info.GetValue<string>("type");
    }

    public void Serialize(IXunitSerializationInfo info)
    {
        info.AddValue("type", type, typeof(string));
    }

    public override string ToString()
    {
        return $"Type = {type}";
    }
}

テスト

public static IEnumerable<object[]> GetClients()
{
    yield return new object[] { new TestClientBuilder("clientType1") };
    yield return new object[] { new TestClientBuilder("clientType2") };
}

[Theory]
[MemberData(nameof(GetClients))]
private void ClientTheory(TestClientBuilder clientBuilder)
{
    var client = clientBuilder.Build();
    // ... test here
}

ターゲット オブジェクトがインジェクトされなくなったのは少し面倒ですが、ビルダーを呼び出すためのコードが 1 行余分にあるだけです。そして、私のテストはパスする (そして 2 回表示される!) ので、不満はありません。

于 2015-08-26T05:55:04.483 に答える
1

今のところ、ReSharper は、カスタム クラスがオーバーライドするときに、カスタム パラメーターを使用してすべての MemberData テストを表示できますToString()

例えば ​​:

public static TheoryData<Permission, Permission, Permission> GetAddRuleData()
{
    var data = new TheoryData<Permission, Permission, Permission>
    {
        {
            new Permission("book", new[] {"read"}, null),
            new Permission("book", new[] {"delete"}, new[] {"2333"}),
            new Permission("book", new[] {"delete", "read"}, new[] {"*", "2333"})
        },
        {
            new Permission("book", new[] {"read"}, null),
            new Permission("music", new[] {"read"}, new[] {"2333"}), new Permission
            {
                Resources = new Dictionary<string, ResourceRule>
                {
                    ["book"] = new ResourceRule("book", new[] {"read"}, null),
                    ["music"] = new ResourceRule("music", new[] {"read"}, new[] {"2333"}),
                }
            }
        }
    };
    return data;
}

Permissionoverrides ToString()、次に ReSharper テスト セッション エクスプローラーで:

xunitR#

于 2018-07-18T01:45:41.477 に答える