C#中的FsCheck:生成具有相同形状的二维数组的列表

问题描述:

假设我正在编写一些视频分析代码。这里是一个视频类的简化版本: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(); 
} 

以库尔特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属性,这是一个很好的选择! –

就在一时冲动草图 - 未编译:)

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

这给了我一个很好的开始,但在编译之前我必须稍微摆动一下:) –