ScalaCheck / QuickCheck を試す (2) [Scala]
前回 [1] の記事を書いた後 ScalaCheck の生成しているテストケースにちょっと疑問を感じたので引き続きいろいろ試してみたらどうにも理不尽な現象に気がついた。
まず「任意の整数は10より小さい」という馬鹿みたいな性質をテストしてみる。
scala> check(property((x:Int) => x < 10)) *** Failed, after 20 successful tests: The arguments that caused the failure was: List(20) res0: scalacheck.TestStats = TestStats(TestFailed(List(20)),20,0) scala> check(property((x:Int) => x < 10)) *** Failed, after 15 successful tests: The arguments that caused the failure was: List(13) res1: scalacheck.TestStats = TestStats(TestFailed(List(13)),15,0) scala> check(property((x:Int) => x < 10)) *** Failed, after 12 successful tests: The arguments that caused the failure was: List(11) res2: scalacheck.TestStats = TestStats(TestFailed(List(11)),12,0)
当然テストにパスしない。で、これを「任意の整数は100より小さい」に置き換えてみる。
scala> check(property((x:Int) => x < 100)) +++ OK, passed 100 tests. res3: scalacheck.TestStats = TestStats(TestPassed(),100,0) scala> check(property((x:Int) => x < 100)) +++ OK, passed 100 tests. res4: scalacheck.TestStats = TestStats(TestPassed(),100,0) scala> check(property((x:Int) => x < 100)) +++ OK, passed 100 tests. res5: scalacheck.TestStats = TestStats(TestPassed(),100,0)
馬鹿馬鹿しさ加減は変わらないのにこんどはテストにパスするようになってしまった。
最初これは ScalaCheck のバグかと思った(まだ 0.2 だし)のだが、本家の QuickCheck でも同様だった。
Hugs.Base> :load Test.QuickCheck Test.QuickCheck> quickCheck $ \x -> x < (10::Int) Falsifiable, after 31 tests: 14 Test.QuickCheck> quickCheck $ \x -> x < (10::Int) Falsifiable, after 50 tests: 21 Test.QuickCheck> quickCheck $ \x -> x < (10::Int) Falsifiable, after 36 tests: 11 Test.QuickCheck> quickCheck $ \x -> x < (10::Int) Falsifiable, after 23 tests: 12 Test.QuickCheck> quickCheck $ \x -> x < (10::Int) Falsifiable, after 24 tests: 14 Test.QuickCheck> quickCheck $ \x -> x < (10::Int) Falsifiable, after 31 tests: 10 Test.QuickCheck> quickCheck $ \x -> x < (10::Int) Falsifiable, after 32 tests: 18 Test.QuickCheck> quickCheck $ \x -> x < (10::Int) Falsifiable, after 59 tests: 23 Test.QuickCheck> quickCheck $ \x -> x < (10::Int) Falsifiable, after 18 tests: 11 Test.QuickCheck> quickCheck $ \x -> x < (10::Int) Falsifiable, after 19 tests: 10 Test.QuickCheck> quickCheck $ \x -> x < (35::Int) OK, passed 100 tests. Test.QuickCheck> quickCheck $ \x -> x < (35::Int) OK, passed 100 tests. Test.QuickCheck> quickCheck $ \x -> x < (35::Int) OK, passed 100 tests. Test.QuickCheck> quickCheck $ \x -> x < (35::Int) OK, passed 100 tests. Test.QuickCheck> quickCheck $ \x -> x < (35::Int) Falsifiable, after 99 tests: 37 Test.QuickCheck> quickCheck $ \x -> x < (35::Int) Falsifiable, after 95 tests: 38 Test.QuickCheck> quickCheck $ \x -> x < (35::Int) Falsifiable, after 84 tests: 38 Test.QuickCheck> quickCheck $ \x -> x < (35::Int) OK, passed 100 tests. Test.QuickCheck> quickCheck $ \x -> x < (35::Int) Falsifiable, after 87 tests: 44 Test.QuickCheck> quickCheck $ \x -> x < (35::Int) OK, passed 100 tests. Test.QuickCheck> quickCheck $ \x -> x < (100::Int) OK, passed 100 tests. Test.QuickCheck> quickCheck $ \x -> x < (100::Int) OK, passed 100 tests. Test.QuickCheck> quickCheck $ \x -> x < (100::Int) OK, passed 100 tests. Test.QuickCheck> quickCheck $ \x -> x < (100::Int) OK, passed 100 tests. Test.QuickCheck> quickCheck $ \x -> x < (100::Int) OK, passed 100 tests. Test.QuickCheck> quickCheck $ \x -> x < (100::Int) OK, passed 100 tests. Test.QuickCheck> quickCheck $ \x -> x < (100::Int) OK, passed 100 tests. Test.QuickCheck> quickCheck $ \x -> x < (100::Int) OK, passed 100 tests. Test.QuickCheck> quickCheck $ \x -> x < (100::Int) OK, passed 100 tests. Test.QuickCheck> quickCheck $ \x -> x < (100::Int) OK, passed 100 tests.
これって ScalaCheck/QuickCheck は Int の範囲の値から等確率で値を選び出すんじゃなくて0あたりから始めて最初のほうほど選ばれる確率が高いみたいな実装なのだろうか。もしそうだとしたらかなり不便というかこのままではまったく使えない気がするのだけど、こんな事実が知られていないわけでもないだろうから何か合理的な理由があってみんな納得して使っているのだろうか。それとも使い方を間違えているのかな。
コメント 4