erlang でテストファースト
先日、erlang でテストを書くモジュールは無いのか?(id:cooldaemon:20070910:1189392523)と書いたところ、jijixi's diary - ユニットテストフレームワーク , 契約プログラミング , ほにほにネタ数点で eunit を教えて頂いたので、早速使ってみた。
インストール
cean で cean:intlall(eunit). もしくは
% svn co http://svn.process-one.net/contribs/trunk/eunit
とする。
使い方
まず、試しにテストを記述した foo.erl を準備する。
-module(foo). -author('cooldaemon@gmail.com'). -include("eunit.hrl"). -export([bar/0, bar/1]). bar_test_() -> [ ?_assert(bar() == buz), ?_assert(bar(1) == 2), ?_assert(bar(2) == 3) ]. bar() -> buz. bar(N) -> N + 1.
eunit.hrl を include すると assert 用に定義されたマクロが使えるようになる。
次にコンパイルする。
% erlc -pa ./eunit/ebin -I./eunit/include foo.erl
この時、eunit の ebin と include を指定するのを忘れないようにする。
最後にテストを実行すると…
% erl -pa ./eunit/ebin -s foo test -s init stop Erlang (BEAM) emulator version 5.5.3 [source] [async-threads:0] [hipe] Eshell V5.5.3 (abort with ^G) 1> All 3 tests successful.
bar_test_/0 を下記のように書き換えてテストを行うと…
bar_test_() -> [ ?_assert(bar() == buz), ?_assert(bar(1) == 4), ?_assert(bar(2) == 3) ].
下記のように出力される。
1> foo:11:bar_test_...*failed* ::error:{assertion_failed,[{module,foo}, {line,11}, {expression,"bar ( 1 ) == 4"}, {expected,true}, {value,false}]} in function foo:'-bar_test_/0-fun-2-'/0 ======================================================= Failed: 1. Aborted: 0. Skipped: 0. Succeeded: 2.
テスト対象モジュールにテストを含む事に関して
jijixi's diary - ユニットテストフレームワーク , 契約プログラミング , ほにほにネタ数点
eunit のちょっと変わった特徴としては、おそらくテスト対象のモジュールソースにテストをそのまま突っ込んでしまえることじゃないかと思う (上記の例ではやってないけど)。NOTEST マクロが定義されていると、コンパイル時にテスト関数 (*_test) は自動的に削られるので、beam ファイルに余計なものが含まれないようにできる (はず……確かめてないけど、eunit_striptests.erl とか見るとそないな感じ)。
社内のプログラムなら良いかなーと思います。
配布目的の場合は、利用者に eunit の使用を強要したくないので、ファイルを分けた方が良いと思います。
yamd の Makfile では、こんな感じにしました。
test.mk
EUNIT=/path/to/eunit
Makefile(一部抜粋)
include ../test.mk #省略 subdirs: @for d in $(SUB_DIRECTORIES); do \ (cd $$d; $(MAKE)); \ done #省略 test: subdirs @for d in $(SUB_DIRECTORIES); do \ (cd $$d; $(MAKE) test); \ done @echo Testing... @erl -noshell -pa ebin -pa $(EUNIT)/ebin -s yamd_test test -s init stop
src/Makefile(一部抜粋)
include ../test.mk #省略 TEST_SOURCES=yamd_test.erl TEST_OBJECTS=$(TEST_SOURCES:%.erl=$(EBIN)/%.$(EMULATOR)) #省略 $(TEST_OBJECTS): $(TEST_SOURCES) erlc -pa $(EBIN) -pa $(EUNIT)/ebin -W $(ERL_COMPILE_FLAGS) -I$(INCLUDE) -I$(EUNIT)/include -o$(EBIN) $< test: $(TEST_OBJECTS)
make all ではテストを行わず、make test の時だけ yamd_test.erl をコンパイルしてテストを行うようにしています。
ちなみに eunit のライセンスは LGPL である為、私が作ったモノと一緒に配布したくないと考えてます。まー好みの問題ですね。
LGPL を勘違いしてた。LGPL はライセンスの伝染しないんですね。eunit を一緒に配布する事も検討しよう。