Help us understand the problem. What is going on with this article?

EUnitでapplicationを起動したテストを書く

More than 5 years have passed since last update.

EUnitでapplicationを起動したテストを書く

EUnitでapplicationを起動したテストを書こうとした場合, いくつか嵌まりどころがあったので纏めておく.

もちろん, mockライブラリの「meck」を使用するという方法もあるが, ここではそれについては触れない.

on_loadで起動する方法 (悪い例)

hoge_tests.erl
-module(hoge_tests).

-include_lib("eunit/include/eunit.hrl").
-on_load(init/0).

hoge_test_() ->
    %% 省略

init() ->
    _ = application:ensure_all_started(app).
    ok.

元々はNIF用に用意されているのだと思うのだが, moduleがloadされた際に実行する関数を指定することができる.
これを使って, applicationの起動が必要なテストはここで起動処理を書いたりしていた.
ただ, 本来の用途でないだけあって困ったことがいくつかある.

テスト終了後の挙動

on_loadで起動したアプリケーションは, test終了後exit(Pid, kill)で終了される.これによる副作用がある.

applicationにはloadに関するステータスとして

  • loaded
  • loading

そして, startに関するステータスとして

  • started
  • running

が存在するが(ちなみに, これらはapplication:info/0を呼ぶことで取得することができる), exitされるとrunningからは消えるがstartedに残るという現象が発生する.
そして, application:ensure_all_started/1startedに存在するアプリケーションについては実行しない.

結果, 他のテストで同じアプリケーションを使用した際にstartできなくなる.
(ちなみに, application:stop/1を呼ぶとstartできるようになる)

on_loadの処理を失敗した場合

そして, もう1つはon_loadを失敗した場合だ.

ついつい調子に乗って

init() ->
    ?assertMatch({ok, _}, application:ensure_all_started(hoge)),
    ok.

とか書くと痛い目に合う.
on_loadokが返らなかった場合, そのモジュールのテストが実行されないからだ.
(多分ロード自体がされないと思うが調べていない)

testが実行されなければ失敗もしないので (つまりtest件数が減るだけ), 何が何でもokを返さないといけない.

setupを用いてネストする方法 (正しい例)

このように困ったことがある訳だが, 単にこれは正しい書き方ではないからこうなっているだけであって, 正しい書き方をすれば良いだけの話だ.

hoge_tests.erl
%% 省略
hoge_test_() ->
    {setup,
     fun()        -> {ok, Started} = application:ensure_all_started(hoge), Started end,
     fun(Started) -> [application:stop(App) || App <- Started] end,
     [
       hoge_test_main(),
       hoge_test_main2()
     ]}.

hoge_test_main() ->
    [
      {"hoge", ?_assertEqual(...)},
      {"fugo", ?_assertEqual(...)}
    ]. 

hoge_test_main2() ->
    [
      %% 省略
    ].

多少面倒にはなるが, なんら問題はない.
数が多くなってくると多少面倒ではあるが...

まとめ

つまるところ今までon_loadを使っていた訳だが, applicationが正常に終了されない為によるテスト間依存が発生していた.

Common Test (CT) を書くというのも1つの手ではあるが, 手軽さのコストが違うので, これで書けるところは書いていきたい.


とはいえ, Erlangを書き始めて半年なので正直なところ, これが本当に正しいかは分からない.
もし, こちらの方が良いというものがあればご教授願いたい.

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away