Подтвердить что ты не робот

FsCheck в С#: сгенерирует список двух размерных массивов с одинаковой формой

Скажем, я пишу код для видеоанализа. Вот упрощенная версия класса Video:

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();
}
4b9b3361

Ответ 1

Используя Kurt Schelfthout ответ в качестве основы, вы можете написать произвольное для класса 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

Здесь, как использовать Video Arbitrary с обычным ванильным FsCheck, здесь размещен в тестовом примере xUnit.net, который не требуется: вы можете разместить его в любом из процессов, которые вы предпочитаете:

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

Prop.ForAll очень полезен для определения свойств с пользовательскими Arbitraries. Когда вы вызываете QuickCheckThrowOnFailure, он будет запускать тест для значений "все" (по defailt: 100) класса video.

Нетипированное свойство 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 - объединить его с Prop.ForAll:

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

Обратите внимание, что возвращаемый тип этого метода больше не void, а Property; атрибут [Property] понимает этот тип и соответственно выполняет тест.

Этот третий вариант - это мой предпочтительный способ использования пользовательских Arbitraries изнутри xUnit.net, поскольку он возвращает проверку времени компиляции.

Ответ 2

Просто подсказка момента эскиза - не скомпилирована:)

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