Nunit: TestCaseSourceAttributeのジェネリック型パラメーターをサポートする

作成日 2017年11月15日  ·  4コメント  ·  ソース: nunit/nunit

私はジェネリックスを使用してより適切に設計される可能性のあるいくつかのテストケースに取り組んでいます。 TestCaseSourceをさまざまなタイプの組み合わせで使用しようとしています。

私が直面している問題は、テストでリフレクションを使用して、オブジェクトの検証に使用する一般的なテストメソッドを呼び出すことです。

[TestFixture]
public class SomeTests
{
    public static IEnumerable<TestCaseData> TestCases()
    {
        yield return
            new TestCaseData(
                typeof(Foo),
                typeof(Bar),
                Generator.Foo,
                Assertions.Foo);
        yield return
            new TestCaseData(
                typeof(Bar),
                typeof(Foo),
                Generator.Bar,
                Assertions.Bar);
    }

    [TestCaseSource(nameof(TestCases))]
    public void CheckSomeTypes(
        Type sourceType,
        Type destinationType,
        TSource source,
        Action<object, object> assert)
    {
        GetType()
            .GetMethod(nameof(CheckSomeTypesImpl), BindingFlags.Public | BindingFlags.Instance)
            .MakeGenericType(new[] { sourceType, destinationType })
            .Invoke(this, new object[] { source, assert });
    }

    public void CheckSomeTypesImpl<TSource, TDestination>(
        TSource source,
        Action<TSource, TDestination> assert)
    {
        var destination = Mapper.Map<TSource, TDestination>(source);

        // Assert are equiviliant
        assert(source, destination);
    }
}

ただし、この場合、次の設計が付加価値をもたらす可能性があると思います。

[TestFixture]
public class SomeTests
{
    public static IEnumerable<TestCaseData> TestCases()
    {
        yield return
            new TestCaseData(
                typeof(Foo),
                typeof(Bar),
                Generator.Foo,
                Assertions.Foo);
        yield return
            new TestCaseData(
                typeof(Bar),
                typeof(Foo),
                Generator.Bar,
                Assertions.Bar);
    }

    [TestCaseSource(nameof(TestCases))]
    public void CheckSomeTypes<TSource, TDestination>(
        TSource source,
        Action<TSource, TDestination> assert)
    {
        var destination = Mapper.Map<TSource, TDestination>(source);

        // Assert are equiviliant
        assert(source, destination);
    }
}

public class Foo
{
    public string Qux { get; set; }
}

public class Bar
{
    public string Qux { get; set; }
}

public static class Generator
{
    public static Foo Foo =>
        new Foo { Qux = "TestTestTest" };
    public static Bar Bar =>
        new Foo { Bar = "AnotherAnotherAnother" };
}

public static class Mapper
{
    // Generic mapper function
    public static TDestination Map<TSource, TDestination>(TSource source)
    {
        if (typeof(TSource) == typeof(Foo))
        {
            return Map((Foo) source);
        }

        if (typeof(TSource) == typeof(Bar))
        {
            return Map((Bar) source);
        }

        throw new NotImplementedException($"No mapping for {typeof(TSource).FullName}.");
    }

    public static Foo Map(Bar bar)
    {
        return new Foo { Qux = bar.Qux };
    }

    public static Bar Map(Foo foo)
    {
        return new Bar { Qux = foo.Qux };
    }
}

public static class Assertions
{
    public static Action<Foo, Bar> Foo =>
        (foo, bar) => Assert.AreEqual(foo.Qux, bar.Qux);
    public static Action<Bar, Foo> Bar =>
        (bar, foo) => Assert.AreEqual(bar.Qux, foo.Qux);
}

これをサポートするために、ローカルでTestCaseSourceAttributeに拡張を行いました。

これは貢献の余地がありますか? PRを作成する前に、まずデザインを明確にしたいと思います。

design enhancement

最も参考になるコメント

それもうまくいくかもしれません。 @ nunit / framework-team、他の誰かがこのトピックを面白いと思いますか?

全てのコメント4件

これは貢献の余地がありますか? PRを作成する前に、まずデザインを明確にしたいと思います。

会話を始めて助けてくれてありがとう。 PRを作成する前にデザインも明確にしたいと思います。 = D間もなく、寄付を受け付けてしまう可能性があります。

同じ質問ですが、$#$ 1 $#$ではなくTestCaseSourceAttribute TestCaseAttributeの場合: https ://github.com/nunit/nunit/issues/1215
推論のみ: https ://github.com/nunit/nunit/issues/150

今日はすでに次善のコードを書かなければならないので、絶対にこれが欲しいです。

TestCaseDataコンストラクターでは、ジェネリックメソッドパラメーターを埋めるType値と、通常のメソッドパラメーターを埋めるType値をより視覚的に区別する方法があると思いますか?

発見可能性について: new TestCaseData<T1, T2>(ordinaryArg1, ordinaryArg2)?どうですか

または、これにより、N個の新しいTestCaseDataクラスの宣言を回避できます。
TestCaseData.Create<T1, T2>(ordinaryArg1, ordinaryArg2, ordinaryArg3)

Returnsメソッドに似たTestCaseData.GenericsArgs(params Type []ジェネリック)のようなメソッドを使用するのはどうですか。

それもうまくいくかもしれません。 @ nunit / framework-team、他の誰かがこのトピックを面白いと思いますか?

この問題はアイデア/デザイン/ディスカッションとしてマークされていますが、何年も貢献していないので、締めくくります。 誰かがこのアイデアに取り組むことに興味がある場合は、あなたの興味を投稿してください。チームは再開を検討します。

このページは役に立ちましたか?
0 / 5 - 0 評価