web-dev-qa-db-fra.com

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

Existe-t-il des moyens dans le cadre 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 distincts 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 va générer 5 tests distincts et comparer 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é?

89
UserControl

xUnit offre un moyen d'exécuter tests paramétrés à travers 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_correctly teste une fois pour chaque InlineDataAttribute 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 manière de procéder est de créer de nouveaux attributs qui inspectent et agissent éventuellement sur les arguments et renvoient la valeur des méthodes de test.

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

124
Enrico Campidoglio

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);
}
47
Sevenate

A 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 comme 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, vous avez donc une bonne marge de manœuvre pour la réutilisation.

18
LewisM

J'ai trouvé une bibliothèque qui produit des fonctionnalités équivalentes à [Values] attribut appelé Xunit.Combinatorial :

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
}
9
Adam

Selon cet article dans 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 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 },
    };
8
itim

J'ai pris en compte toutes les réponses ici et j'ai également utilisé les types génériques TheoryData<,> De XUnit pour me donner des définitions de données simples, faciles à lire et à saisir pour l'attribut 'MemberData' sur 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} ");
}

Three tests runs observed from test Explorer for 'My First Test'


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