omake + oUnitでTDD!
明日は、TDD Bootcamp名古屋です。
というわけで、自分のoUnit + omakeでTDDな環境を晒してみます。もっとクールな方法があったら教えてください><。
ちなみに、構築したサンプルはGitHub - mzp/ounit-example-1: OUnit exampleに置いてあります。
ディレクトリ構造
ディレクトリ構造はこんな感じで、本番コード(./src)とテストコード(./test)が別ディレクトリに分かれています。
. |-- OMakefile |-- OMakeroot |-- src | |-- OMakefile | |-- fact.ml | `-- main.ml `-- test |-- OMakefile `-- fact_test.ml
ルートのOMakefile
ルートのOMakefileではサブディレクトリを認識させます。ついでにocamlfindも有効にしておきます。
.PHONY: all clean check USE_OCAMLFIND = true OCAML_FLAGS=-w A -warn-error A if $(not $(OCAMLFIND_EXISTS)) eprintln(This project requires ocamlfind, but is was not found.) eprintln(You need to install ocamlfind and run "omake --configure".) exit 1 NATIVE_ENABLED = $(OCAMLOPT_EXISTS) BYTE_ENABLED = $(not $(OCAMLOPT_EXISTS)) .SUBDIRS: src test clean: rm -f *~ *.opt *.cmi *.cmx *.o *.omc
本番コード側
適当なモジュールを書きます。とりあえず階乗で。
(* src/fact.ml *) let rec fact n = if n = 0 then 2 (* BUGGGGYYYY *) else n * (fact (n - 1))
そしてOMakefile。
普通のOCamlプログラムとしてビルドするだけでなく、ライブラリとしてもビルドします。
# src/OMakefile .PHONY: all clean FILES[] = fact main LIB = target PROGRAM = main .DEFAULT: $(OCamlProgram $(PROGRAM), $(FILES)) OCamlLibrary($(LIB), $(FILES)) clean: rm -f *~ *.opt *.cmi *.cmx *.o *.omc *.cma *.cmxa $(PROGRAM) *.a
テストコード側
oUnitを使ったテストコードを書きます。
(* test/fact_test.ml *) open OUnit open Fact let _ = run_test_tt_main begin "fact.ml" >::: [ "fact(3)" >:: begin fun () -> assert_equal 6 (fact 3) end ] end
そしてテストプログラムをビルドします。
このとき先ほど作ったライブラリを使うようにします。
# test/OMakefile .PHONY: all clean check OCAMLINCLUDES += ../src FILES[] = fact_test OCAMLPACKS[] = oUnit PROGRAM = test OCAML_LIBS += ../src/target clean: rm -f *~ *.opt *.cmi *.cmx *.o *.omc *.cma *.cmxa .DEFAULT: all all : $(OCamlProgram $(PROGRAM), $(FILES)) check : all ./$(PROGRAM)
実行例
$ omake check *** omake: reading OMakefiles *** omake: finished reading OMakefiles (0.23 sec) - build test <check> + ./test F ====================================================================== Failure: 1:0:fact OUnit: not equal ---------------------------------------------------------------------- Ran: 1 tests in: 0.00 seconds. FAILED: Cases: 1 Tried: 1 Errors: 0 Failures: 1 Skip:0 Todo:0 *** omake: 38/40 targets are up to date *** omake: failed (4.16 sec, 0/3 scans, 7/14 rules, 13/130 digests) *** omake: targets were not rebuilt because of errors: <phony <test/check>>