この記事は Elixir Advent Calendar 2023 シリーズ2 20日目の記事です。
TL;DR
Elixir のテストで爆速にスタブを書きたかったら、Hex のライブラリ Mimic を使うとよいです。
概要
テストはソフトウェア開発において重要な役割を果たしますが、外部依存関係や API の呼び出しによって複雑化することがあったりします。
Elixir のエコシステムでは、これらの課題を解決する選択肢の1つに Mimic というライブラリがあります。
この記事では、Mimic を使用して Elixir のテストでスタブを簡単に実装する方法を紹介します。
Mimic とは?
Mimic は、Elixir のテスト実行中に外部モジュールの関数呼び出しをオーバーライドする ためのライブラリです。
Mimic を使用すると、テスト中に特定の関数が返すべき値を簡単に制御できるようになります。これにより、外部APIの呼び出しやその他の外部依存関係をスタブすることが可能になります。
なお、Mimic の作者 edgurgel さんは、他にも HTTPoison などの各種 Elixir ライブラリを開発されてる方です。
実行環境
- Elixir 1.15.7 (compiled with Erlang/OTP 26)
- Phoenix v1.7
セットアップ
Mimicをプロジェクトに追加するには、mix.exs に以下の依存関係を追加し、mix deps.get
を実行して依存関係をインストールします。
defp deps do
[
... ,
{:mimic, "~> 1.7", only: :test}
]
end
今回の使用例では Timex を test_helper.exs に追記してスタブできるようにします。
(別途 Timex ライブラリの追加 → mix deps.get
も必要)
Mimic.copy(Timex) # <- add
ExUnit.start()
スタブの実装
Mimic を使用したスタブの実装例として、Timex.now
関数のふるまいをスタブ化する手順を示します。
サンプルコードは、現在の日時 を取得しYYYY-MM-DD
形式の文字列にして返すメソッドです。
defmodule SampleApp.DatetimeProcessor do
@spec get_current_date_string() :: String.t()
def get_current_date_string() do
Timex.format!(get_current_datetime(), "{YYYY}-{0M}-{0D}")
end
defp get_current_datetime() do
Timex.now("Asia/Tokyo")
end
end
これに対するテストを書きたいとします。
defmodule SampleApp.DatetimeProcessor.GetCurrentDateStringTest do
use ExUnit.Case
use Mimic
test "Get current datetime and return the YYYY-MM-DD formatted date string." do
stub(
Timex,
:now,
fn "Asia/Tokyo" -> DateTime.from_naive!(~N[2024-01-01 12:00:00], "Asia/Tokyo") end
)
assert SampleApp.DatetimeProcessor.get_current_date_string() == "2024-01-01"
end
end
ここでは、Mimic.stub
によって Timex.now
が "Asia/Tokyo"
タイムゾーンで呼ばれた際に固定の日時を返すよう設定しています。
たったのこれだけで、テストがその関数の実際の実行に依存することなく、任意の結果を返すことができるようになります。
おわりに
Mimic は、外部依存関係のあるテストを書く際の複雑さを減らすための強力なツールです。
中長期的な観点を踏まえれば Mox が技術選択肢に上がってきますが、規模の小さいプロダクトや検証段階において初速を出してまず動くものを作りたいようなケースでは Mimic はとても有用です。
Mimic.reject
みたいな便利なメソッドも揃っているし、Mimic、何より名前がよいので(大事)、Elixir プロジェクトのテスト戦略に Mimic の活用をぜひ検討してみてください。