いまさらだけど、ScalaCheckを使ってみた。
ScalaCheckは、HaskellのQuckCheckのScala版。
QuickCheck: Automatic testing of Haskell programs
Property Based Testingという考え方に基づくテスティングフレームワークで、汎用的に使われるライブラリに対して広範囲で網羅的なテストを書くために使われる。
例えば、以下のようなコードを書くと(この例のテストは必ず成功するので、意味はないけど)……
import org.scalacheck._ @main def propertyCheck = { numProp.check() } val numProp = Prop.forAll(Gen.choose(1, 10)) { n => Prop.collect(n) { n == n } }
以下のような結果が出てくる。
collect
は実際に生成された値を確かめるための関数で、これでテストコードをラップしておくと実際に生成された値と、その割合が確認できる。
[info] running propertyCheck + OK, passed 100 tests. > Collected test data: 14% 3 13% 7 12% 10 11% 2 10% 9 10% 4 10% 1 8% 5 7% 6 5% 8
ランダムに100個の1〜10までの数値が生成され、テストコードのインプットとなる。これにより自分で手作りしたParameterized Testingのパラメータより網羅度が上がる、という訳です。ただし、独自のデータ構造に適した、整合性が担保されたデータを自動生成するには、それなりのコード量を書くことになり、費用対効果を見てProperty Based Testingなのか、Parameterized Testingなのかを決めていくことになるでしょう。
この例では、日付や時刻のテストにScalaCheckを使っていますが、それなりにコード書くね、と。
ちなみにcollect
関数はSeq[T]
に対して挙動がおかしくなる問題が有って、最もシンプルなList[Int]
が上手く動かず、1時間くらい溶かしてしまった...
確実にに使うなら、引数に必ずtoString
で文字列に変換した結果を渡した方がいいかもしれない。
Functional Programming in Scala, Second Edition
のサンプルコードが、1st Editionの時と違って、全面的にProperty Based Testingの独自ライブラリ(本の中で後半に出てくるProperty Based Testingのサンプル実装)で全体をテストするように書き直されていて、それはそれでいいけど、最初から用意されているテストコードを通るように、コードを書くだけだとちょっと理解が浅くなるなーと思って、同じものをScalaCheckで書き直してみたくなって使い始めたところ...でも、自動生成にハマり過ぎると、本末転倒感が有るので、使い方はほどほどに、という感じですかね。