ทดสอบการกำหนดพารามิเตอร์ใน xUnit.net คล้ายกับ NUnit


108

มีวิธีการใดในกรอบงาน 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 แบบแยกกันใน NUnit GUI

[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 และชอบมาก แต่มันขาดคุณสมบัติเหล่านี้ ขาดไม่ได้เลย มีอะไรเปลี่ยนแปลงไปไหม?


คำแนะนำฉบับสมบูรณ์ที่ส่งวัตถุที่ซับซ้อนเป็นพารามิเตอร์ไปยังวิธีการทดสอบประเภทที่ซับซ้อนในการทดสอบหน่วย
Iman Bahrampour

คำตอบ:


139

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
เห็นได้ชัดว่าไม่อนุญาตให้ใช้ตัวอักษรทศนิยมเป็นพารามิเตอร์แอตทริบิวต์
Sergii Volchkov

1
ไม่พบ @RubenBartelink ลิงก์ของคุณ ไปที่นี่แทน: blog.benhall.me.uk/2008/01/introduction-to-xunit-net-extensions
Ronnie Overby

9
คุณจะต้องใช้xUnit.net: Extensions (NuGet Package) ไม่เช่นนั้น[Theory]จะไม่มีแอตทริบิวต์
Daniel AA Pelsmaeker

4
มันจะดีมากถ้าเฟรมเวิร์กการทดสอบหน่วย. NET ที่ได้รับการแนะนำมากที่สุดมีเอกสารประกอบ ..
Isaac Kleinman

6
Google ระบุว่า SO คำตอบของคุณคือเอกสาร xUnit
nathanchere

55

ขอผมส่งตัวอย่างอีก 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);
}

คุณลืมวงเล็บปิดในบรรทัดที่ 2 หรือไม่?
cs0815

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 คุณมีตัวเลือก "parametrization" สามตัวเลือก:

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

การทดสอบสามครั้งที่สังเกตจากนักสำรวจการทดสอบสำหรับ 'การทดสอบครั้งแรกของฉัน'


NB ใช้ VS2017 (15.3.3), C # 7, & XUnit 2.2.0 สำหรับ. NET Core


น่ารักขนาดนี้
Brett Rowberry
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.