[Elixir]macroのテストを書いてみる

macroのテストを書く

macroのテストでは、通常は

  • コンパイルされたモジュールの振る舞い
  • コンパイルされた結果(AST)自体

の2つの側面をテスト対象と見てテストコードを書いていくことになります。

振る舞いに関しては、以下のような感じでExUnitを使います。こちらは、普通にmacroによって定義された関数を使って、期待するinput/outputを確認する、というものです。

ExUnit.start
Code.require_file "target.exs", __DIR__

defmodule TargetTest do
  use ExUnit.Case

  test "title" do
    # do something  
    assert target, expected

  end
end

コンパイル自体に対しては、以下のようにAST自体が正しくできているか?を確認することになります。他は↑とさほど変わりません。inputがASTの文字列、outputがassertionになります。

例えば、以下のような内容になります。

  test "t/3 raises KeyError when bindings not provided" do
    assert Sample.compile([]) |> Macro.to_string == String.strip ~S"""
    (
      def(t(locale, path, bindings \\ []))
      []
      def(t(_locale, _path, _bindings)) do
        {:error, :no_translation}
      end
    )
    """
  end

少し話が逸れますが、Agentなどのテストにおいて、Processにsendされた値を確認したい時があります。つまり、mailboxの中身を確認したい。そんな時は以下のように __mailbox__ を使うことができます。

iex> send self, :sample_message
iex> ExUnit.Assertions.__mailbox__(self())
". Process mailbox:n:sample_message"

いつMacroを使うか?

  • より簡潔にコードを記述できる場合
  • コード生成が必要な場合
    • 例えば、Phoenixのルーティングではコード生成によってGET/POST/PUT/PATCH/DELETEなどの match を定義しています。
    • このような、少量のコードを書くことで、大量の汎用的なコードを生成する、というような場合、それら全てを手で書くよりも正しく、効率的に実行コードを生成できます

ただし、複雑になると理解が難しくなるので、metaprogramingで大事なことは、simpleであることです。

mix-inするとき、 import を使えるなら use は使わない

use を使うと、 __using__ を読み込みます。そのため、mix-inとしてimportのように使うことができます。ただ、macroをmix-inのためだけに使うのは止めましょう。単に複雑さを増すので。

  • macroを使ったmix-in: NO
defmodule Sample do
  defmacro __using__(_option) do
    def something(do) do
      # process
    end
  end
end

defmodle Neko do
  use Sample

  def inu do
    something do
  end
end
  • importを使ったmix-in: OK
defmodule Sample do
  def something do
    # process
  end
end


defmodle Neko do
  import Sample

  def inu do
    something do
  end
end

他、いろいろありましたが大事なところはここら辺かな。

ここまでの内容は、『Metaprogramming Elixir』を読んだ内容が主でした。 __using__ の使い所とか、テストフレームワークとか作るのに必要なメタプログラミングの知見を得られたかな、という感じで、良い学びでした。ついでに、ちょくちょくElixir関連のOSSに貢献できたので、それも良かったかな 🙂

関連

広告

[Elixir]macroのテストを書いてみる” への1件のフィードバック

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中