web-dev-qa-db-ja.com

NUnitに似たxUnit.netでのパラメーター化のテスト

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

これにより、NUnit GUIで8つの個別のテストが生成されます

_[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を試してみましたが、気に入っていましたが、これらの機能が欠けていました。それらなしでは生きていけない。何か変わったことがありますか?

89
UserControl

xUnit は、data theoriesと呼ばれるものを介してparameterized testsを実行する方法を提供します。この概念はNUnitにあるものと同等ですが、すぐに使用できる機能は完全ではありません。

以下に例を示します。

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

この例では、xUnitは指定された値を引数として渡すたびにInlineDataAttributeごとにShould_format_the_currency_value_correctlyテストを1回実行します。

データ理論は拡張ポイントであり、これを使用して、パラメータ化されたテストを実行する新しい方法を作成できます。これを行う方法は、テストメソッドの引数と戻り値を検査し、オプションで動作する新しい属性を作成することです。

AutoFixtureAutoData および InlineAutoData の理論で、xUnitのデータ理論を拡張する方法の実用的な例を見つけることができます。

124

誰かに時間を節約できるように、ここでもう1つサンプルを投げてみましょう。

[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

最初のリクエストで、 here にある例に従うことができます。

テストのコレクションに必要なデータを含む静的クラスを構築できます

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の最初の引数を使用すると、データソースとして使用するメンバーを定義できるため、再利用に関してかなりの柔軟性が得られます。

18
LewisM

Xunit.Combinatorial というNUnitの[Values]属性と同等の機能を生成するライブラリを見つけました。

パラメーターレベルの値を指定できます。

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

XUnitの この記事 によると、3つの「パラメーター化」オプションがあります。

  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 },
    };
8
itim

ここですべての回答をオンボードし、さらにXUnitのTheoryData<,>次の例のように、テストの「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} ");
}

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


NB 2017.15の使用(.3.3)、C#7、および.NET CoreのXUnit 2.2.0
6
Peter