Использование FsCheck для генерации записей - PullRequest
1 голос
/ 30 октября 2019

Я хотел бы использовать FsCheck (с XUnit) для создания записей типа: type QueryRequest = {Symbol: string; StartDate: DateTime; EndDate: DateTime}, где Symbol ограничен тремя вариантами - ORCL, IBM, AAPL и StartDate иEndDate ограничены диапазоном между 1 января 2000 г. и 1 января 2019 г. .

Однако мне неясно, как действовать дальше. Должен ли я использовать Arb.generate<T> или Arb.Default или какую-либо другую утилиту, на которой будет основано создание и сжатие тестовых случаев?


Обновление 1

Дополнительный вопрос, связанный с проблемами, генерирующими записи, доступен здесь .

Original:
{ Symbol = ""
  StartDate = 8/9/2057 4:07:10 AM
  EndDate = 10/14/2013 6:15:32 PM }
Shrunk:
{ Symbol = ""
  StartDate = 8/9/2057 12:00:00 AM
  EndDate = 10/14/2013 12:00:00 AM }

Обновление 2

Ниже приведен код набора тестов:

namespace Parser

open Xunit
open FsCheck.Xunit
open DataGenerators

module Tests =
    [<Fact>]
    let ``sanity check`` () =
        let expected = true
        let actual = true
        Assert.Equal(expected, actual)

    [<Property(Arbitrary = [|typeof<StockTwitGenerator>|])>]
    let ``validate queries`` (q: QueryRecord) =
        q.EndDate > q.StartDate

Ответы [ 2 ]

2 голосов
/ 30 октября 2019

Arb.filter фильтрует генератор и усадку для данного произвольного экземпляра, чтобы содержать только те значения, которые соответствуют данной функции фильтра. Это должно помочь вам удовлетворить ваши потребности.

https://fscheck.github.io/FsCheck/TestData.html#Useful-methods-on-the-Arb-module https://github.com/fscheck/FsCheck/blob/master/src/FsCheck/ArbitraryExtensions.fs#L17-17

1 голос
/ 30 октября 2019

Если у вас есть ограничения, ограничивающие значения небольшим подмножеством всех разрешенных значений для данного типа, создание допустимого значения проще и безопаснее 1 , чем фильтрация.

Учитывая...

open FsCheck
open System

type QueryRequest = {Symbol: string; StartDate: DateTime; EndDate: DateTime}

... мы можем начать с создания генератора символов:

let symbols = ["ORCL"; "IBM"; "AAPL"]
let symbol = Gen.elements symbols

и диапазона дат

let minDate = DateTime(2000, 1, 1)
let maxDate = DateTime(2019, 1, 1)
let dateRange = maxDate - minDate
let date =
    Gen.choose (0, int dateRange.TotalDays)
    |> Gen.map (float >> minDate.AddDays)

Обратите внимание, что Gen.choose принимает только диапазон int. Мы можем обойти, сгенерировав случайное смещение максимально допустимой разницы дат, а затем сопоставив его с DateTime

Используя их, мы можем построить генератор для QueryRequest s ...

let query =
    gen {
        let! s = symbol
        let! d1 = date
        let! d2 = date
        let startDate, endDate = if d1 < d2 then d1, d2 else d2, d1 
        return { Symbol = s; StartDate = startDate; EndDate = endDate }
    }

type MyGenerators =
  static member QueryRequest() =
      {new Arbitrary<QueryRequest>() with
          override _.Generator = query }

... зарегистрируйтесь ...

Arb.register<MyGenerators>()

и, наконец, проверьте:

let test { Symbol = s; StartDate = startDate; EndDate = endDate } =
    symbols |> Seq.contains s && startDate >= minDate && endDate <= maxDate && startDate <= endDate

Check.Quick test

1 Документация FsCheck

Убедитесь, что существует высокая вероятность того, что предикат удовлетворен.

...