Tester le paramétrage dans xUnit.net similaire à NUnit

107

Y a-t-il des moyens dans le framework xUnit.net similaires aux fonctionnalités suivantes de NUnit?

[Test, TestCaseSource("CurrencySamples")]
public void Format_Currency(decimal value, string expected){}

static object[][] CurrencySamples = new object[][]
{
    new object[]{ 0m, "0,00"},
    new object[]{ 0.0004m, "0,00"},
    new object[]{ 5m, "5,00"},
    new object[]{ 5.1m, "5,10"},
    new object[]{ 5.12m, "5,12"},
    new object[]{ 5.1234m, "5,12"},
    new object[]{ 5.1250m, "5,13"}, // round
    new object[]{ 5.1299m, "5,13"}, // round
}

Cela générera 8 tests séparés dans l'interface graphique NUnit

[TestCase((string)null, Result = "1")]
[TestCase("", Result = "1")]
[TestCase(" ", Result = "1")]
[TestCase("1", Result = "2")]
[TestCase(" 1 ", Result = "2")]
public string IncrementDocNumber(string lastNum) { return "some"; }

Cela générera 5 tests séparés et comparera automatiquement les résultats ( Assert.Equal()).

[Test]
public void StateTest(
    [Values(1, 10)]
    int input,
    [Values(State.Initial, State.Rejected, State.Stopped)]
    DocumentType docType
){}

Cela générera 6 tests combinatoires. Inestimable.

Il y a quelques années, j'ai essayé xUnit et j'ai adoré mais il manquait ces fonctionnalités. Je ne peux pas vivre sans eux. Quelque chose a-t-il changé?

UserControl
la source
Un guide complet qui envoie des objets complexes en tant que paramètre aux types complexes de
Iman Bahrampour

Réponses:

139

xUnit offre un moyen d'exécuter des tests paramétrés via quelque chose appelé théories des données . Le concept est équivalent à celui trouvé dans NUnit mais la fonctionnalité que vous obtenez hors de la boîte n'est pas aussi complète.

Voici un exemple:

[Theory]
[InlineData("Foo")]
[InlineData(9)]
[InlineData(true)]
public void Should_be_assigned_different_values(object value)
{
    Assert.NotNull(value);
}

Dans cet exemple, xUnit exécutera le Should_format_the_currency_value_correctlytest une fois pour chaqueInlineDataAttribute chaque fois en passant la valeur spécifiée comme argument.

Les théories des données sont un point d'extensibilité que vous pouvez utiliser pour créer de nouvelles façons d'exécuter vos tests paramétrés. La façon dont cela est fait est de créer de nouveaux attributs qui inspectent et agissent éventuellement sur les arguments et la valeur de retour des méthodes de test.

Vous pouvez trouver un bon exemple concret de la façon dont les théories de données de xUnit peuvent être étendues dans AutoFixture de Autodata et InlineAutoData théories.

Enrico Campidoglio
la source
3
Apparemment, il n'est pas permis d'utiliser des littéraux décimaux comme paramètres d'attribut.
Sergii Volchkov
1
@RubenBartelink votre lien est introuvable. Allez plutôt ici: blog.benhall.me.uk/2008/01/introduction-to-xunit-net-extensions
Ronnie Overby le
9
Vous aurez besoin de xUnit.net: Extensions (NuGet Package) ou sinon l' [Theory]attribut n'est pas disponible.
Daniel AA Pelsmaeker
4
Ce serait formidable si le framework de test unitaire .NET le plus recommandé avait de la documentation.
Isaac Kleinman
6
Google dit que vos réponses SO SONT la documentation xUnit.
nathanchere
55

Permettez-moi de jeter un autre échantillon ici, juste au cas où cela ferait gagner du temps à quelqu'un.

[Theory]
[InlineData("goodnight moon", "moon", true)]
[InlineData("hello world", "hi", false)]
public void Contains(string input, string sub, bool expected)
{
    var actual = input.Contains(sub);
    Assert.Equal(expected, actual);
}
Sevenate
la source
Avez-vous oublié une parenthèse fermante dans la 2ème ligne?
cs0815
Utile, merci :)
Zeek2
21

Lors de votre première demande, vous pouvez suivre les exemples trouvés ici .

Vous pouvez construire une classe statique contenant les données nécessaires à une collection de tests

using System.Collections.Generic;

namespace PropertyDataDrivenTests
{
    public static class DemoPropertyDataSource
    {
        private static readonly List<object[]> _data = new List<object[]>
            {
                new object[] {1, true},
                new object[] {2, false},
                new object[] {-1, false},
                new object[] {0, false}
            };

        public static IEnumerable<object[]> TestData
        {
            get { return _data; }
        }
    }
}

Ensuite, à l'aide de l'attribut MemberData, définissez le test en tant que tel

public class TestFile1
{
    [Theory]
    [MemberData("TestData", MemberType = typeof(DemoPropertyDataSource))]
    public void SampleTest1(int number, bool expectedResult)
    {
        var sut = new CheckThisNumber(1);
        var result = sut.CheckIfEqual(number);
        Assert.Equal(result, expectedResult);
    }
}

ou si vous utilisez C # 6.0,

[Theory]
[MemberData(nameof(PropertyDataDrivenTests.TestData), MemberType = typeof(DemoPropertyDataSource))]

Le premier argument de MemberDataAttribute vous permet de définir le membre que vous utilisez comme source de données, de sorte que vous disposez d'une assez grande flexibilité lors de la réutilisation.

LewisM
la source
13

Selon cet article de xUnit, vous avez trois options de "paramétrage":

  1. InlineData
  2. ClassData
  3. MemberData

Exemple InlineData

[Theory]
[InlineData(1, 2)]
[InlineData(-4, -6)]
[InlineData(2, 4)]
public void FooTest(int value1, int value2)
{
    Assert.True(value1 + value2 < 7)
}

Exemple de ClassData

public class BarTestData : IEnumerable<object[]>
{
    public IEnumerator<object[]> GetEnumerator()
    {
        yield return new object[] { 1, 2 };
        yield return new object[] { -4, -6 };
        yield return new object[] { 2, 4 };
    }

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}


[Theory]
[ClassData(typeof(BarTestData))]
public void BarTest(int value1, int value2)
{
    Assert.True(value1 + value2 < 7)
}

Exemple MemberData

[Theory]
[MemberData(nameof(BazTestData))]
public void BazTest(int value1, int value2)
{
    Assert.True(value1 + value2 < 7)
}

public static IEnumerable<object[]> BazTestData => new List<object[]>
    {
        new object[] { 1, 2 },
        new object[] { -4, -6 },
        new object[] { 2, 4 },
    };
itim
la source
12

J'ai trouvé une bibliothèque qui produit une fonctionnalité équivalente à l' [Values]attribut de NUnit appelé Xunit .

Il vous permet de spécifier des valeurs au niveau des paramètres:

[Theory, CombinatorialData]
public void CheckValidAge([CombinatorialValues(5, 18, 21, 25)] int age, 
    bool friendlyOfficer)
{
    // This will run with all combinations:
    // 5  true
    // 18 true
    // 21 true
    // 25 true
    // 5  false
    // 18 false
    // 21 false
    // 25 false
}

Ou vous pouvez implicitement lui faire comprendre le nombre minimal d'appels pour couvrir toutes les combinaisons possibles:

[Theory, PairwiseData]
public void CheckValidAge(bool p1, bool p2, bool p3)
{
    // Pairwise generates these 4 test cases:
    // false false false
    // false true  true
    // true  false true
    // true  true  false
}
Adam
la source
6

J'ai pris en compte toutes les réponses ici et j'ai également utilisé les TheoryData<,>types génériques de XUnit pour me donner des définitions de données simples, faciles à lire et à taper en toute sécurité pour l'attribut 'MemberData' de mon test, comme dans cet exemple:

/// must be public & static for MemberDataAttr to use
public static TheoryData<int, bool, string> DataForTest1 = new TheoryData<int, bool, string> {
    { 1, true, "First" },
    { 2, false, "Second" },
    { 3, true, "Third" }
};

[Theory(DisplayName = "My First Test"), MemberData(nameof(DataForTest1))]
public void Test1(int valA, bool valB, string valC)
{
    Debug.WriteLine($"Running {nameof(Test1)} with values: {valA}, {valB} & {valC} ");
}

Trois exécutions de tests observées à partir de l'explorateur de tests pour «Mon premier test»


NB Utilisation de VS2017 (15.3.3), C # 7 et XUnit 2.2.0 pour .NET Core

Peter
la source
C'est adorable.
Brett Rowberry