PROBLEM

  • Elixirをさわりはじめてしばらく経つけどふかく理解した気になれない
  • Phoenixやほかのフレームワークに頼られないケースが出てきたとき自由な発想ができるようになっておきたい
  • 巷でいわれているSLA 99.9999999% などの実際がどうなのか腹落ちしてない

-

SOLUTION

というわけで、LYSE本を読むことにした。Elixirに関係ありそうな箇所を選定している。

  • 今回は単体テストEUnitについてかんがえる。

EUnitの特徴

  • eunit:test(モジュール名, [verbose]) で実行
  • postfixがtestの関数 _test() に対してテストをおこなう
  • モジュールの内外ともにテストコードをかける
  • モジュール外に書いた場合プライベート関数に対するテストはできなくなる
  • テスト用モジュールはpostfixがtestsとなる _tests.erl

EUnitの関数

  • 表現系
    • テスト
      • foo_test -> ?assert(is_number(ops:add(1, 2))), ?assertEqual(4, ops:add(2, 2)).
    • テストジェネレータ
      • foo_test_ -> [test_them_1(), test_them_2, ?_assertError(badarith, 1/0)].
    • フィクスチャー
      • setup
        • {setup, Setup, Instantiator}
        • {setup, Setup, Cleanup, Instantiator}
        • {setup, Where, Setup, Instantiator}
        • {setup, Where, Setup, Cleanup, Instantiator}
      • foreach
        • {foreach, Setup, [Instantiator]}
        • {foreach, Setup, Cleanup, [Instantiator]}
        • {foreach, Where, Setup, [Instantiator]}
        • {foreach, Where, Setup, Cleanup, [Instantiator]}
      • instantiator制御
        • {spawn, TestSet} - 並行処理
        • {timeout, (時間 秒), TestSet} - 時間指定処理
        • {inorder, TestSet} - 逐次処理
        • {inparallel, TestSet} - 並列処理
      • コメント
        • {Comment, Fixture}
  • アサーション系
    • ?assert(expression)
    • ?assertNot(expression)
    • ?assertEqual(A, B)
    • ?assertMatch(Pattern, Expression)
    • ?assertError(Pattern, Expression)
    • ?assertThrow(Pattern, Expression)
    • ?assertExit(Pattern, Expression)
    • ?assertException(Class, Pattern, Expression)

フィクスチャー (foreach) をつかったテストジェネレータ

-define(setup(F), {setup, fun start/0, fun stop/1, F}).

%% 関数some2について
some2_test_() ->
    [{"SetupData1を適切に評価できること",
      {foreach,
       ?setup(fun (SetupData1) ->
           [some_instantiator1(SetupData1),
            some_instantiator2(SetupData1),
            ...
            some_instantiatorN(SetupData1)]
       end}},
     {"SetupData2を並列処理で適切に評価できること",
      {foreach,
       ?setup(fun (SetupData2) ->
           {inparallel,
            [some_instantiator1(SetupData2),
             some_instantiator2(SetupData2),
             ...
             some_instantiatorN(SetupData2)]}
       end)}}].

並列・並行でテストする際の注意点

  • 名前をa、b、cのようにハードコードすると、並列で走らせている際、名前の衝突が起きる可能性がある。可能な限り名前はハードコードせずに make_ref() によって一意の値をつかうこと。

-

以上 :droplet: