にむかひて

Phoenixでtrait

2022年4月 トップ > ひとこと > 調査したことの記録
#Elixir #Phoenix #trait

テスト時に利用するfixture()でいくつかのパターンのデータを定義したい

  • RailsにおけるFactoryBotのTraitsのイメージ
  • どこかにありそうだけど、手元でやってみる

利用イメージ

  • user_fixture([:japanese])
  • user_fixture(email: "test@example.com")
  • user_fixture([:japanese, email: "test@example.com"])
  • user_fixture([:japanese, :male, email: "test@example.com"])

実装

test/support/data_trait.ex

  • 各fixtureモジュールでuseできるようにモジュールを定義
  • 引数を再帰的に処理する
    • Atomなら_traitに引き渡す。このatomに相当する処理を各fixtureモジュール側に実装する
    • List([{:email, "test@example.com}])なら、マージしてしまう
defmodule DataTrait do
  def trait do
    quote do
      defp trait(obj, []), do: obj

      defp trait(obj, [head | tail]) when is_atom(head) do
        _trait(obj, head) |> trait(tail)
      end

      defp trait(obj, list) do
        obj
        |> Map.merge(Map.new(list))
      end

      defp _trait(obj, :touch), do: obj
    end
  end

  defmacro __using__([]) do
    apply(__MODULE__, :trait, [])
  end
end

test/support/fixtures/user_fixtures.ex

  • 対応する_trait()を実装する
defmodule UsersFixtures do
  use DataTrait

  def user_fixture(traits \\ []) do
    %User{}
    |> trait(traits)
    |> Repo.insert!()
  end

  defp _trait(user, :japanese),
    do: Map.put(user, :language, "japanese")

  defp _trait(user, :male),
    do: Map.put(user, :sex, "male")
end

結論

  • 複雑なものだと辛そうではあるが、基本的なパターンなら問題なさそう(かな)
  • 複雑な準備は user_fixture() ではなく user_hoge_fixture() みたいにするからいいかな、たぶん…

サイト内検索