Kotest ジェネレーター操作(Generator Operations)
Kotest ジェネレーター操作(Generator Operations)として、Next、Filter、Map、FlatMap、Merging、Bind を紹介する。
Next
プロパティテストでなくても、値を返すためだけに Arb を使用したい場合は、次を呼び出せばよい。
val arbA: Arb<A> = ...
val a = arbA.next() // use Random.Default
val a2 = arbA.next(rs) // pass in Random
Filter
Arb があり、値のサブセットを提供する新しい Arb を作成したい場合は、元の Arb で filter を呼び出すことができる。たとえば、偶数を生成する 1 つの方法は、整数ジェネレーターを取得して奇数値をフィルタリングすることである。
val evens = Arb.int().filter { it.value % 2 == 0 }
val odds = Arb.int().filter { it.value % 2 == 1 }
Map
Arb があり、生成された値を変換したい場合は map を使用できる。
val integerStrings: Arb<String> = Arb.int().map { it.toString() }
FlatMap
放出値またはエッジケースが以前の任意放出値に依存する arb がある場合は、flatMap を使用できる。
val dependentArbs: Arb<String> = Arb.of("foo", "bar").flatMap { prefix ->
Arb.int(1..10).map { integer ->
"${prefix}-${integer}"
}
}
Merging
2 つのジェネレーターをマージして、結果要素が両方のジェネレーターから均等にサンプリングされるようにできる。
val merged = arbA.merge(arbB)
そのため、次の例では各ランダムサンプルで "A" または "B" が出る確率が同じになる。
val a = arbitrary { "a" }
val b = arbitrary { "b" }
val ab = a.merge(b)
println(ab.take(1000).groupingBy { it }.eachCount())
// {a=493, b=507}
3 つ以上の arbitrary オブジェクトをマージする場合は、Arb.choice または Arb.choose の方が適していることがある。たとえば次のように使用できる。
Arb.choice(arbA, arbB, arbC)はarbA、arbB、arbCの間で均一サンプリングするために使用できる。- また、各 arbitrary の頻度をより細かく制御するには
Arb.choose(4 to arbA, 1 to arbB, 5 to arbC)を使用できる。この例では、arbA、arbB、arbCがそれぞれ 40%、10%、50% の確率でサンプリングされる。
Bind
Bind は、複数の任意値を適用したい場合に便利である。bind を使ってデータクラスの値を構築する方法を見てみる。
data class Person(val name: String, val age: Int)
val personArb: Arb<Person> = Arb.bind(
Arb.string(),
Arb.int()
) { name, age -> Person(name, age) }