Тестова параметризація в xUnit.net схожа на NUnit


106

Чи є в рамках xUnit.net засоби, подібні до наступних особливостей 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
}

Це дозволить створити 8 окремих тестів у GUI 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"; }

Це дозволить генерувати 5 окремих тестів і автоматично порівнювати результати ( Assert.Equal()).

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

Це дасть 6 комбінаторних тестів. Безцінне.

Кілька років тому я спробував xUnit і сподобався, але у нього не було цих функцій. Не можу жити без них. Щось змінилося?


Повне керівництво, яке надсилає складні об'єкти як параметр методам тестування складних типів в
Тестовому

Відповіді:


138

xUnit пропонує спосіб запустити параметризовані тести через те, що називається теоріями даних . Концепція еквівалентна тій, що знаходиться в NUnit, але функціонал, який ви отримуєте з коробки, не настільки повно.

Ось приклад:

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

У цьому прикладі xUnit буде виконувати Should_format_the_currency_value_correctlyтест один раз для InlineDataAttributeкожного разу, передаючи вказане значення як аргумент.

Теорії даних - це точка розширюваності, яку ви можете використовувати для створення нових способів запуску параметрів тестування. Це робиться шляхом створення нових атрибутів, які перевіряють та необов'язково діють на аргументи та повертають значення методів тестування.

Ви можете знайти хороший практичний приклад того , як теорії даних XUnit може бути розширено в AutoFixture «s Autodata і InlineAutoData теорій.


3
Мабуть, заборонено використовувати десяткові літери в якості параметрів атрибутів.
Сергій Волчков

1
@RubenBartelink ваше посилання не знайдено. Зайдіть сюди замість: blog.benhall.me.uk/2008/01/introduction-to-xunit-net-extensions
Ронні Овербі

9
Вам знадобиться xUnit.net: розширення (NuGet Package) або інший [Theory]атрибут недоступний.
Daniel AA Pelsmaeker

4
Було б чудово, якби найбільш рекомендований .NET Framework тестування рамки мав деяку документацію ..
Ісаак Клейнман

6
Google каже, що ваші ТАКОВІ відповіді - це документація xUnit.
натанчере

55

Дозвольте сюди кинути ще один зразок, про всяк випадок, коли це хтось заощадить.

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

Ви забули кронштейн для закриття у другому рядку?
cs0815

Корисно, дякую :)
Zeek2

21

На ваш перший запит ви можете наслідувати приклади, знайдені тут .

Ви можете побудувати статичний клас, що містить дані, необхідні для збору тестів

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

Потім, використовуючи атрибут MemberData, визначте тест як такий

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

або якщо ви використовуєте C # 6.0,

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

Перший аргумент MemberDataAttribute дозволяє визначити члена, який ви використовуєте як джерело даних, тому у вас є достатня кількість гнучкості при повторному використанні.


13

Відповідно до цієї статті в xUnit у вас є три варіанти "параметризації":

  1. InlineData
  2. ClassData
  3. MemberData

Приклад InlineData

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

Приклад 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)
}

Приклад 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 },
    };

12

Я знайшов бібліотеку, яка виробляє еквівалентну функціональність [Values]атрибуту NUnit під назвою Xunit.Combinatorial :

Це дозволяє задати значення рівня параметрів:

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

Або ви можете неявно визначити мінімальну кількість викликів для покриття всіх можливих комбінацій:

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

6

Я взяв на борт всі відповіді тут і додатково використав TheoryData<,>загальні типи XUnit, щоб дати мені прості, легкі для читання та введення безпечні визначення даних для атрибута 'MemberData' на моєму тесті, як показано на цьому прикладі:

/// 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} ");
}

Три тести, які спостерігаються у тестового провідника для "Мого першого тесту"


Примітка: Використання VS2017 (15.3.3), C # 7 та XUnit 2.2.0 для .NET Core


Це прекрасно.
Бретт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.