Превращение генератора на основе System.Random в генератор FsCheck
Предположим, мне дали генератор на основе System.Random
и я хочу превратить его в генератор FsCheck:
let myGen = MyGen(System.Random())
let fsGen = gen { return myGen.Generate() }
Есть несколько проблем с этим простым решением: во-первых, концепция размера игнорируется; Я думаю, что это не большая проблема, хотя многие генераторы игнорируют размер. Другая проблема влияет на воспроизводимость, потому что генераторы FsCheck являются чистыми функциями под капотом, случайность обеспечивается только механизмом выборки в тестовом средстве. (это четко объясняется в этом ответе).
Теперь решение может быть:
let fsGen =
gen {
let! seed = Gen.choose(0, System.Int32.MaxValue)
let myGen = MyGen(System.Random(seed))
return myGen.Generate() }
но есть снижение производительности, потому что я должен создать новый экземпляр MyGen
каждый раз (с потенциально высокой стоимостью инициализации)
Есть ли лучший способ?
1 ответ
Может ли следующая работа? Даже если MyGen
случайный характер, вы можете сделать его детерминированным, зафиксировав начальное число:
let deterministicGen = MyGen(Random(42))
Из-за характера Random
это не гарантирует достаточно случайное распределение, но если это имеет место для ваших целей, вы можете создать детерминированную последовательность значений, генерируемых MyGen
:
let deterministicValues = List.init 100 (fun _ -> deterministicGen.Generate())
Это только 100 значений, но в зависимости от ваших потребностей, вы можете создать больший выборочный набор из 1000 или, возможно, даже 10000 значений.
Как deterministicGen
, deterministicValues
исправлено: это список значений, сгенерированных MyGen
,
Вы можете легко попросить FsCheck случайным образом выбрать значения из этого списка:
let fsGen = Gen.elements deterministicValues
Вот, fsGen
является Gen<'a>
, где 'a
что угодно MyGen.Generate()
возвращается.