2015-09-27 52 views
12

假設我正在編寫一些視頻分析代碼。這裏是一個視頻類的簡化版本:C#中的FsCheck:生成具有相同形狀的二維數組的列表

public class Video 
{ 
    public readonly int Width; 
    public readonly int Height; 
    public readonly List<int[,]> Frames; 

    public Video(int width, int height, IEnumerable<int[,]> frames) 
    { 
     Width = width; 
     Height = height; 
     Frames = new List<int[,]>(); 
     foreach (var frame in frames) 
     { 
      if (frame.GetLength(0) != height || frame.GetLength(1) != width) 
      { 
       throw new ArgumentException("Incorrect frames dimensions"); 
      } 
      Frames.Add(frame); 
     } 
    } 
} 

如何使一個Arbitrary<Video>並註冊了嗎?我如何爲這個任意做一個收縮器?

試過,不明白如何應用工程:

public static Arbitrary<Video> Videos() 
{ 
    var videoGen = Arb.Generate<PositiveInt>() 
     .SelectMany(w => Arb.Generate<PositiveInt>(), (w, h) => new {w, h}) 
     .Apply(/* what is Gen<Func<a,b>> */); 

    return videoGen.ToArbitrary(); 
} 

想這一點,但在這裏不能堵塞發電機清單:

public static Arbitrary<Video> Videos() 
{ 
    var videoGen = Arb.Generate<PositiveInt>() 
     .SelectMany(w => Arb.Generate<PositiveInt>(), (w, h) => new Video(w, h, /* how to plug generator here? */)); 

    return videoGen.ToArbitrary(); 
} 

回答

12

以庫爾特Schelfthout的答案爲基礎,你可以寫一個任意的fo r是video類是這樣的:

public static class VideoArbitrary 
{ 
    public static Arbitrary<Video> Videos() 
    { 
     var genVideo = from w in Arb.Generate<PositiveInt>() 
         from h in Arb.Generate<PositiveInt>() 
         from arrs in Gen.ListOf(
          Gen.Array2DOf<int>(
           h.Item, 
           w.Item, 
           Arb.Generate<int>())) 
         select new Video(w.Item, h.Item, arrs); 
     return genVideo.ToArbitrary(); 
    } 
} 

您可以以不同的方式使用它。

普通的香草FsCheck

以下是如何與普通的香草FsCheck,一個xUnit.net測試用例內這裏舉辦,這是不需要使用視頻武斷,你可以在你喜歡的任何過程舉辦這樣的:

[Fact] 
public void VideoProperty() 
{ 
    var property = Prop.ForAll(
     VideoArbitrary.Videos(), 
     video => 
     { 
      // Test goes here... 
      Assert.NotNull(video); 
     }); 
    property.QuickCheckThrowOnFailure(); 
} 

Prop.ForAll對於用自定義仲裁來定義屬性非常有用。當您致電QuickCheckThrowOnFailure時,它將運行Video類的「全部」(通過defailt:100)值的測試。

非類型化xUnit.net財產

您也可以使用FsCheck.Xunit膠圖書館,但你必須要通過任意一個弱類型值屬性:

[Property(Arbitrary = new[] { typeof(VideoArbitrary) })] 
public void XunitPropertyWithWeaklyTypedArbitrary(Video video) 
{ 
    // Test goes here... 
    Assert.NotNull(video); 
} 

這很簡單並且容易理解,但在分配Arbitrary屬性時沒有涉及靜態類型檢查,所以我不太喜歡這種方法。

類型化xUnit.net財產

一種更好的方式來使用FsCheck.Xunit定製Arbitraries是combine it with Prop.ForAll

[Property] 
public Property XUnitPropertyWithStronglyTypedArbitrary() 
{ 
    return Prop.ForAll(
     VideoArbitrary.Videos(), 
     video => 
     { 
      // Test goes here... 
      Assert.NotNull(video); 
     }); 
} 

注意,這個方法的返回類型不再void,但Property ; [Property]屬性理解此類型並相應地執行測試。

第三個選項是我在xUnit.net中使用自定義仲裁的首選方式,因爲它會帶來編譯時檢查。

+2

我不知道鍵入的xUnit.net屬性,這是一個很好的選擇! –

6

就在一時衝動草圖 - 未編譯:)

var genVideo = from w in Arb.Generate<PositiveInt>() 
       from h in Arb.Generate<PositiveInt>() 
       from arrs in Gen.ListOf(Gen.Array2DOf(h, w, Arb.Generate<int>)) 
       select new Video(w, h, arrs); 
+0

這給了我一個很好的開始,但在編譯之前我必須稍微擺動一下:) –