2014-02-28 7 views
55

Xunit has a nice feature으로 전달하십시오. Theory 속성을 사용하여 하나의 테스트를 만들고 InlineData 속성에 데이터를 넣으면 xUnit이 많은 테스트를 생성하고 테스트합니다.복잡한 매개 변수를 [이론]

나는 이런 식으로 뭔가를 갖고 싶어하지만, 내 방법 매개 변수가 '단순한 데이터'하지 (같은 string, int, double),하지만 내 클래스의 목록 :

public static void WriteReportsToMemoryStream(
    IEnumerable<MyCustomClass> listReport, 
    MemoryStream ms, 
    StreamWriter writer) { ... } 
+1

환경에 적합한 경우 F #에서 노이즈가 훨씬 적습니다. - http://stackoverflow.com/a/35127997/11635 –

답변

91

많은있다 XUnit의 xxxxData 속성 예 : PropertyData 속성을 확인하십시오.

반환 할 수있는 속성을 구현할 수 있습니다 IEnumerable<object[]>. 이 메서드가 생성하는 object[] 각각은 [Theory] 메서드에 대한 단일 호출에 대한 매개 변수로 "압축 해제"됩니다.

다른 옵션은 ClassData이며 동일하게 작동하지만 다른 클래스/네임 스페이스의 테스트간에 '생성자'를 쉽게 공유 할 수 있으며 실제 테스트 방법과 '데이터 생성기'를 분리합니다.

참조 즉 these examples from here :

PropertyData 예

public class StringTests2 
{ 
    [Theory, PropertyData(nameof(SplitCountData))] 
    public void SplitCount(string input, int expectedCount) 
    { 
     var actualCount = input.Split(' ').Count(); 
     Assert.Equal(expectedCount, actualCount); 
    } 

    public static IEnumerable<object[]> SplitCountData 
    { 
     get 
     { 
      // Or this could read from a file. :) 
      return new[] 
      { 
       new object[] { "xUnit", 1 }, 
       new object[] { "is fun", 2 }, 
       new object[] { "to test with", 3 } 
      }; 
     } 
    } 
} 

ClassData 예

public class StringTests3 
{ 
    [Theory, ClassData(typeof(IndexOfData))] 
    public void IndexOf(string input, char letter, int expected) 
    { 
     var actual = input.IndexOf(letter); 
     Assert.Equal(expected, actual); 
    } 
} 

public class IndexOfData : IEnumerable<object[]> 
{ 
    private readonly List<object[]> _data = new List<object[]> 
    { 
     new object[] { "hello world", 'w', 6 }, 
     new object[] { "goodnight moon", 'w', -1 } 
    }; 

    public IEnumerator<object[]> GetEnumerator() 
    { return _data.GetEnumerator(); } 

    IEnumerator IEnumerable.GetEnumerator() 
    { return GetEnumerator(); } 
} 
+0

예 여기있어? 링크가 깨지는 경우를 대비하여 – dcastro

+0

@dcastro : 예, 원본 xunit 문서에서 실제로 검색 중입니다 – quetzalcoatl

+0

흠 .. 찾지 못했습니다. 나는 이것들을 사용할 것이다. – quetzalcoatl

0

내가 여기 당신이 잘못된 것 같아요. 어떤 xUnit Theory 속성이 실제로 의미하는 것 :이 function-under-test가받는 매개 변수로 특수/임의 값을 보내이 함수를 테스트하려고합니다. 즉, 다음 속성 (예 : InlineData, PropertyData, ClassData 등)으로 정의한 내용이 해당 매개 변수의 소스가됩니다. 즉, 이러한 매개 변수를 제공하기 위해 원본 개체를 구성해야합니다. 귀하의 경우에는 소스로 ClassData 개체를 사용해야합니다 같아요. 또한 ClassDataIEnumerable<>에서 상속받습니다. 즉, IEnumerable<>이 값을 생성 할 때까지 생성 된 다른 매개 변수 집합이 테스트 대상 기능의 수신 매개 변수로 사용될 때마다이를 의미합니다. 여기

예 : Tom DuPont .NET

예는 올바르지 않을 수 있습니다 - 나는 케찰코아틀의 대답 @ 업데이트하려면 오랜 시간이

26

에 대한 xUnit의를 사용하지 않았다 [PropertyData]이 인수는 AS 소요 [MemberData]로 대체되었습니다 속성 정적 메서드, 필드 또는 IEnumerable<object[]>을 반환하는 속성의 문자열 이름입니다. (나는 그들이 계산하고로를 산출이 특히 좋은 실제로 한 번에 하나씩 테스트 케이스를 계산할 수 반복자 방법을 찾으십시오.)

이 열거에 의해 반환 된 시퀀스의 각 요소는 object[]입니다 각 배열은 길이가 같아야하며 길이는 테스트 케이스에 대한 인수의 수 여야합니다 (속성 [MemberData]으로 주석 처리되며 각 요소는 해당 메소드 매개 변수와 동일한 유형이어야합니다 (또는 변환 유형, 나는 모른다.)

(release notes for xUnit.net March 2014the actual patch with example code 참조)

+0

약간의 수정 ... 당신은'[MemberData]'를 의미 했습니까? 나는 당신의 링크 중 어느 하나에서'[MethodData]'에 관해서 아무 것도 볼 수 없다. – rkyser

+0

@rkyser 죄송합니다. 나는 고칠 것이다. – davidbak

2

당신은이 방법으로 시도 할 수 있습니다. 익명 객체 배열되어 생성

public class TestCase 
{ 
    public static readonly List<object[]> IsSaturdayTestCase = new List<object[]> 
    { 
     new object[]{new DateTime(2016,1,23),true}, 
     new object[]{new DateTime(2016,1,24),false} 
    }; 

    public static IEnumerable<object[]> IsSaturdayIndex 
    { 
     get 
     { 
     List<object[]> tmp = new List<object[]>(); 
      for (int i = 0; i < IsSaturdayTestCase.Count; i++) 
       tmp.Add(new object[] { i }); 
     return tmp; 
     } 
    } 
} 
6

:

public class TestClass { 

    bool isSaturday(DateTime dt) 
    { 
     string day = dt.DayOfWeek.ToString(); 
     return (day == "Saturday"); 
    } 

    [Theory] 
    [MemberData("IsSaturdayIndex", MemberType = typeof(TestCase))] 
    public void test(int i) 
    { 
     // parse test case 
     var input = TestCase.IsSaturdayTestCase[i]; 
     DateTime dt = (DateTime)input[0]; 
     bool expected = (bool)input[1]; 

     // test 
     bool result = isSaturday(dt); 
     result.Should().Be(expected); 
    } 
} 

는 테스트 데이터를 보유 할 다른 클래스를 만들기를 데이터를 구성하는 가장 쉬운 방법이 아니므로 프로젝트에서이 패턴을 사용했습니다.

먼저

public class IngredientTests : TestBase 
{ 
    [Theory] 
    [MemberData(nameof(IsValidData))] 
    public void IsValid(Ingredient ingredient, string testDescription, bool expectedResult) 
    { 
     Assert.True(ingredient.IsValid == expectedResult, testDescription); 
    } 

    public static IEnumerable<object[]> IsValidData 
    { 
     get 
     { 
      var food = new Food(); 
      var quantity = new Quantity(); 
      var data= new List<ITheoryDatum>(); 

      data.Add(TheoryDatum.Factory(new Ingredient { Food = food }      , false, "Quantity missing")); 
      data.Add(TheoryDatum.Factory(new Ingredient { Quantity = quantity }    , false, "Food missing")); 
      data.Add(TheoryDatum.Factory(new Ingredient { Quantity = quantity, Food = food } , true, "Valid")); 

      return data.ConvertAll(d => d.ToParameterArray()); 
     } 
    } 
} 

문자열 Description 속성은 자신에게 때 뼈를 던져하는 것입니다 ... 개별 테스트 및 회원 데이터를 작성하기 쉽고 깨끗

//http://stackoverflow.com/questions/22093843 
public interface ITheoryDatum 
{ 
    object[] ToParameterArray(); 
} 

public abstract class TheoryDatum : ITheoryDatum 
{ 
    public abstract object[] ToParameterArray(); 

    public static ITheoryDatum Factory<TSystemUnderTest, TExecptedOutput>(TSystemUnderTest sut, TExecptedOutput expectedOutput, string description) 
    { 
     var datum= new TheoryDatum<TSystemUnderTest, TExecptedOutput>(); 
     datum.SystemUnderTest = sut; 
     datum.Description = description; 
     datum.ExpectedOutput = expectedOutput; 
     return datum; 
    } 
} 

public class TheoryDatum<TSystemUnderTest, TExecptedOutput> : TheoryDatum 
{ 
    public TSystemUnderTest SystemUnderTest { get; set; } 

    public string Description { get; set; } 

    public TExecptedOutput ExpectedOutput { get; set; } 

    public override object[] ToParameterArray() 
    { 
     var output = new object[3]; 
     output[0] = SystemUnderTest; 
     output[1] = ExpectedOutput; 
     output[2] = Description; 
     return output; 
    } 

} 

이제 일부 재사용, 공유 클래스를 정의 많은 테스트 케이스 중 하나가 실패합니다.

+0

나는 이것을 좋아한다. 90+ 속성에 대한 유효성을 검증해야하는 매우 복잡한 객체에 대한 잠재력이 있습니다. 간단한 JSON 객체를 전달하고이를 비 직렬화하고 테스트 반복을위한 데이터를 생성 할 수있다. 잘 했어. – Gustyn