1. k1complete

    Posted

    k1complete
Changes in title
+elixirでmeckをつかう
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,120 @@
+meckはmockをerlangで実現するモジュールですがelixirでも使えます
+
+# 使いかた
+
+```elixir:mix.exs
+ defp deps do
+ [ { :meck, "~> 0.1", github: "exproxus/meck" } ]
+ end
+```
+
+を入れておきます。これでmix deps.compileすることで、自分のプロジェクトでmeckが
+使えるようになります。
+
+# モックの生成
+
+テストコード中で
+
+```
+ :meck.new(Module, [:passthrough])
+```
+
+これでModuleがモックになります。:passthroughというのは、モックとして仕込ん
+でいない関数が呼ばれたときには本物を呼び出すという指定。passthrough以外
+にもいろいろ指定できるが詳しくはmeckのドキュメントを参照のこと。このままだと
+ただ本物にフォワードするだけのモックなので、芸を仕込みます。
+
+作られたモックに芸を仕込むのはいくつかの方法があります。
+
+方法1
+
+ :meck.expect(Module, :func, fn(args) -> returnvalue end)
+
+関数funcに対して無名函數を対応付ける方法でです。自由度が高いが煩雑に
+慣るきらいがあるので通常はもっとベタな方法をつかいます。
+
+方法2
+
+ :meck.expect(Module, :func, [{args_spec1, ret_spec1},
+ {args_spec2, ret_spec2},...])
+
+関数funcに対して引数スペックと戻り値スペックペアのリストを指定する、極
+めてベタな方法です。書式だけ見ると分かりにくいかもしれないけど、実際に
+書いてみると、極めてベタ。
+
+引数スペックは、値を書けばよいが、簡単なパターンマッチも使える。
+任意の値を示す"_"はアトムとしての:"_"を用いる。
+
+戻り値スペックは、戻値の他に例外の発生の何れかで以下の形式となる。
+
+ ret_spec -> :meck.val(exp) expを返す|
+ :meck.seq(list) listの要素を順に返す|
+ :meck.loop(list) listの要素を繰り返して返す|
+ :meck.raise(:throw, reason) 例外を発生|
+ :meck.raise(:error, reason) エラー例外を発生|
+ :meck.raise(:exit, reason) exit例外を発生
+
+例:
+
+TargetModuleモジュールを開発することがお仕事だとします。
+
+TargetModuleは単純なExternalModuleへのプロキシだとして、こんなかんじに
+実装したとします。
+
+```elixir:target_module.exs
+ defmodule TargetModule do
+ def priv(a) do
+ ExternalModule.priv(a)
+ end
+ end
+```
+
+しかし必要なExternalModuleモジュールはまだまだ開発されていなくて、
+仕様だけが決っているとします。
+ExternalModule.priv/1の仕様として
+
+ ExternalModule.priv("a") -> "a"
+ ExternalModule.priv("b") -> "b"
+ ExternalModule.priv({_, _}) -> "badmatch"
+ ExternalModule.priv(_) -> "c"
+
+だとします。
+このような場合にTargetModule開発者のexunitはどうなるでしょうか。
+
+exunitにはsetupとteardownがありますのでそこで初期化をします。
+
+```elixir:target_module_test.exs
+ setup do
+ :meck.new(ExternalModule, [:passthrough])
+ :meck.expect(ExternalModule, :priv,
+ [
+ {["a"], :meck.val("a")},
+ {["b"], :meck.val("b")},
+ {[{:"_", :"_"}], :meck.raise(:throw, "badmatch")},
+ {[:"_"], :meck.val("c")},
+ ])
+
+ end
+ teardown do
+ :meck.unload(ExternalModule)
+ end
+ ```
+
+このように、極めてベタな感じにモックの振る舞いを記述できます。
+
+これでexunitを動かすとExternalModuleをモックにしたてて、終了するとアンロード
+するようになります。あとは、ガシガシテストを畫いていきます。
+
+```target_module_test.exs:elixir
+ test "priv-mock" do
+ assert("a" == TargetModule.priv("a"))
+ assert("b" == TargetModule.priv("b"))
+ assert("c" == TargetModule.priv("c"))
+ assert("c" == TargetModule.priv("d"))
+ assert catch_throw(TargetModule.priv({"d", "a"})) == "badmatch"
+ end
+ ```
+
+こんなかんじです。
+
+つぎは、@alucky0707 さんです!