これはML Advent Calendar 2016の18日目の記事です。
OCamlのテストフレームワークのOUnitについて解説します。
また、Oasisの簡単な説明も行います。
プロジェクトのセットアップ
OCamlのプロジェクトでは、だいたいの場合はOasisを使います。
Oasisはビルドの為の支援ツールで、ビルドに必要なMakefileやメタ情報を含んだファイルを設定から自動生成できます。
opam install oasis
インストールが完了したら、設定ファイル_oasisを作成し、必要最低限の情報を記述します。
OASISFormat: 0.4 Name: example # プロジェクト名 Version: 0.1.0 # バージョン Synopsis: example # ライブラリの説明 Authors: Noritaka Horio <holy.shared.design@gmail.com> # 著作者 License: MIT # ライセンス Plugins: META (0.4), StdFiles (0.4), DevFiles (0.4) # 使用するプラグイン BuildTools: ocamlbuild # ビルドツール # ライブラリ名 Library example # ソースの場所 Path: src # ビルドするモジュール Modules: Example
もしくは、quickstartコマンドを使用します。
聞かれる質問に答えていくだけで、_oasisファイルを生成できます。
oasis quickstart
_oasisファイルが作成できたら、setupコマンドを実行します。
oasis setup
setupコマンドを実行すると、MakefileやAUTHORS.txt、README.mdなどのファイルが生成されているはずです。
Oasisはプラグインで機能を追加できますが、試す分には下記の3つぐらいで十分です。
プラグイン名 | 説明 |
---|---|
META | ライブラリ用のMETAファイルを生成する |
StdFiles | _oasisの定義から、README.txt, INSTALL.txt, AUTHORS.txtを生成する |
DevFiles | ビルドに必要な、Makefileを生成する(なくてもビルドはできます) |
ライブラリの実装とテストコード
_oasisの設定で、ビルドするライブラリの指定をします。
ライブラリ名とソースの場所、そしてビルドするモジュールをカンマ区切りで列挙します。
# ライブラリ名 Library example # ソースの場所 Path: src # ビルドするモジュール Modules: Example
srcディレクトリを作成して、example.mlファイルを追加して、適当な関数を追加します。
ここでは、文字列を受け取って、文字列をそのまま返す関数を定義します。(解説の為の雑な関数です。)
let say msg = msg
次にこのモジュールのテストコードを書きます。
testsディレクトリを作成して、エントリポイントとなるtest.mlと、モジュール単体のテストコードexample_test.mlを作成します。
テストコードは、OUnitの独自演算子の>::、>:::を使用して記述します。(>:もあるが使うことはないと思う)
example_test.ml
Exampleモジュールのsay関数のテストは、受け取った引数をそのまま返すだけなのでこんな感じになります。
open OUnit2 (* say関数のテスト関数、テストの説明と関数でテストを表現する *) let say_test = "echo string" >:: (fun _ -> assert_equal (Example.say "hello") "hello") (* このテストモジュールのすべてのテストをまとめる *) let tests = "all_tests" >::: [ say_test; ]
test.ml
エントリポイントではrun_test_tt_main関数でテストを実行するようにします。
ここで各テストジュールをまとめて、指定します。
open OUnit2 let all_tests = "all_tests" >::: [ Example_test.tests ] let () = run_test_tt_main all_tests;;
演算子の意味
>::
文字列とテスト関数より、新しいテストを返します。
let some_func1 = true "test desc" >:: (fun ctx -> assert_bool "failed message" (some_func1 ()))
>:::
文字列とテストのリストより、新しいテストを返します。
複数のテストをグルーピングする為に使用します。
let some_func1 = true let some_func2 = false "all_tests" >::: [ "test desc" >:: (fun ctx -> assert_bool "failed message" (some_func1 ())); "test desc" >:: (fun ctx -> assert_bool "failed message" (some_func2 ())) ]
テストコードのビルドとテストの実行
テストコードが追加できたら、_oasisファイルにテスト用の設定を追加します。
# テスト用のバイナリの名前 Executable test # テストコードの場所 Path: tests # テストコードのエントリポイント MainIs: test.ml Build$: flag(tests) # ビルド結果のフォーマット(バイトコードにもできる) CompiledObject: native # 配布する必要がないので、false Install: false # 依存しているモジュールoUnitとテスト対象のライブラリを指定 BuildDepends: oUnit, example Test test Run$: flag(tests) # テストコマンド Command: $test # テストを実行するワーキングディレクトリ WorkingDirectory: tests
テストを実行するには、configureでテスト用に設定を変えた後に、testでテストを実行できます。
これはテストコードを含んだ実行可能なバイナリを生成して、実行しています。
make configure CONFIGUREFLAGS=--enable-tests
make test
まとめ
ここで使用したファイルとかは、ここに適当に書いたOCamlのコードの中にあるので、実物を試したい人はご確認ください。 github.com