OCamlを使っている皆さん。テストコードは書きますよね。
そこでOUnitの登場です。
OUnitはOCamlのユニットテスティングフレームワークです。OSSなどでも良く使われています。
…が、OUnitは結構冗長、というよりテスト自体の本質が見えにくくなることがあります。
そのため、結構シンプルなテスト以外が行われていないOSSもある気がします。(強い静的型付けなのでそれでもバグは少ないのでしょうが…)
そこで(あまりうれしくない部分もありますが)、pa_ounitというライブラリを紹介しておきます。
https://github.com/till-varoquaux/pa_ounit
(JS Core を使っている人はすでにJS Coreに付属しているpa_ounitが入っていると思います。)
「ちょっと気軽な」と書きましたがpa_ounit自体の中身はP4というドキュメント整備されてない類いのツールが使われているので、あまり中身を見るのをお勧めしたくなる代物ではありません…(まだコード自体は短いので複雑なP4を用いたライブラリよりは読めなくもない)
実際にどのようにpa_ounitを使うと書けるか、紹介しましょう。
let fizzbuzz n = if n = 0 then raise Invalid_arg n match n mod 3, n mod 5 with | 0, 0 -> "FizzBuzz" | 0, _ -> "Fizz" | _, 0 -> "Buzz" | _ -> string_of_int n (* 単純なテスト *) TEST "fizzbuzz 1 = 1" = fizzbuzz 1 = "1" TEST "fizzbuzz 3 = Fizz" = fizzbuzz 3 = "Fizz" TEST "fizzbuzz 5 = Buzz" = fizzbuzz 5 = "Buzz" TEST "fizzbuzz 15 = FizzBuzz" = fizzbuzz 15 = "FizzBuzz" (* 例外のテスト *) TEST_FAILS "raise Invalid_argument if the argument is less than 1" RAISES (Invalid_argument _) : string = fizzbuzz 0 TEST_FAILS : string = fizzbuzz ~-1 (* テストをモジュールとしてまとめておく事も出来る *) TEST_MODULE "fizzbuzz_test" = struct TEST = fizzbuzz 1 = "1" TEST = fizzbuzz 3 = "Fizz" TEST = fizzbuzz 5 = "Buzz" TEST = fizzbuzz 15 = "FizzBuzz" end (* ここでテスト実行 *) let _ = OUnit.run_test_tt_main ( ounit_tests() )
上記をfizzbuzz.mlというファイルに書き込んだとしましょう。
そのあと、
$ ocamlfind ocamlopt -package pa_ounit -syntax camlp4o -c fizzbuzz.ml $ ocamlfind ocamlopt -linkpkg -package pa_ounit fizzbuzz.cmx -o fizzbuzz.native $ ./fizzbuzz.native
とすれば、テストが実行できます。もちろんテストコードとプロダクトコードを分離する事も可能です。
非常に簡潔にテストコードが記述できるpa_ounitですが、弱点としては
テスト対象の結果の値が表示されない
これにつきます。
表示する方法があるのかもしれませんが、見つけてません。(多分、ソースコードを見る限り無いと思います。)
テスティングフレームワークとしてメインで使っていくには、結構大きな弱点です。なにせ失敗時の状況が分からないですし。
とはいえ、OUnitだけでは難しいテストコードの複雑さの解消に使えるのではないでしょうか。
こういうのは使い分け、ですね。