Nunit: Unterstützung generischer Typparameter für TestCaseSourceAttribute

Erstellt am 15. Nov. 2017  ·  4Kommentare  ·  Quelle: nunit/nunit

Ich arbeite an einigen Testfällen, die mit Generika besser gestaltet werden können. Ich versuche, TestCaseSource mit vielen verschiedenen Kombinationen von Typen zu verwenden.

Das Problem, auf das ich stoße, ist die Verwendung von Reflektion in meinen Tests, um eine generische Testmethode aufzurufen, die ich für die Objektvalidierung verwende.

[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);
    }
}

Ich glaube jedoch, dass das folgende Design in diesem Fall einen Mehrwert schaffen kann:

[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);
}

Ich habe lokal Erweiterungen für TestCaseSourceAttribute vorgenommen, um dies zu unterstützen.

Ist das etwas für einen Beitrag offen? Ich möchte zuerst das Design klären, bevor ich eine PR erstelle.

design enhancement

Hilfreichster Kommentar

Das könnte auch funktionieren. @nunit/framework-team, findet noch jemand dieses Thema interessant?

Alle 4 Kommentare

Ist das etwas für einen Beitrag offen? Ich möchte zuerst das Design klären, bevor ich eine PR erstelle.

Vielen Dank, dass Sie das Gespräch begonnen und Ihre Hilfe angeboten haben. Wir möchten auch das Design klären, bevor Sie eine PR erstellen. =D Es wird wahrscheinlich bald für einen Beitrag offen sein!

Gleiche Frage, aber für TestCaseAttribute , nicht TestCaseSourceAttribute : https://github.com/nunit/nunit/issues/1215
Nur Inferenz: https://github.com/nunit/nunit/issues/150

Ich muss heute schon suboptimalen Code schreiben, also will ich das unbedingt.

Glauben Sie, dass es im TestCaseData -Konstruktor eine Möglichkeit gibt, Type -Werte, die generische Methodenparameter füllen, visuell besser von Type -Werten zu unterscheiden, die gewöhnliche Methodenparameter füllen?

Für die Auffindbarkeit: was ist mit new TestCaseData<T1, T2>(ordinaryArg1, ordinaryArg2)?

Oder dies, wodurch wir vermeiden würden, N neue TestCaseData -Klassen zu deklarieren:
TestCaseData.Create<T1, T2>(ordinaryArg1, ordinaryArg2, ordinaryArg3)

Wie wäre es mit einer Methode wie TestCaseData.GenericsArgs(params Type[] Generics) ähnlich der Returns-Methode.

Das könnte auch funktionieren. @nunit/framework-team, findet noch jemand dieses Thema interessant?

Diese Ausgabe ist als Idee/Design/Diskussion gekennzeichnet, hatte aber seit Jahren keine Beiträge mehr, also schließe ich. Wenn jemand daran interessiert ist, an dieser Idee zu arbeiten, posten Sie Ihr Interesse und das Team wird eine Wiedereröffnung in Betracht ziehen.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen