備忘録

働きたくないでござる

Elixir の Umbrella プロジェクトで Phoenix アプリケーションを作成 (2)

前回: giraphme.hatenablog.com

前回はモデル作ったので今回はテストを書いていきます。 とはいっても、普通の Elixir アプリケーションのテスト作成とあまり違いはないですが.....。

構成

前回も書きましたが、構成を再掲。

$ tree .
.
├── apps
│   ├── us_core # DB関連のビジネスロジックをもった Elixir アプリケーション ← イマココ
│   └── us_api # REST API を提供する Phoenix アプリケーション
│   └── us_web # React を利用した View を提供する Phoenix アプリケーション
│   └── us_admin_web # 管理画面を提供する Phoenix アプリケーション

DB の準備

テストの前に DB を作っておきます。

$ MIX_ENV=test mix ecto.create
$ MIX_ENV=test mix ecto.migrate

そして、テストのたびに Truncate しないでいいよう、 Ecto.Adapters.SQL.Sandbox の設定をしていきます。

apps/us_core/config/config.exs

if Mix.env == :test do
  config :us_core, UsCore.Repo,
    pool: Ecto.Adapters.SQL.Sandbox
end

apps/us_core/test/test_helper.exs

+ Ecto.Adapters.SQL.Sandbox.mode(UsCore.Repo, :manual)
  ExUnit.start()

apps/us_core/config/config.exs

if Mix.env == :test do
  config :us_core, UsCore.Repo,
    pool: Ecto.Adapters.SQL.Sandbox
end

この状態で、各テストモジュールの中に以下を書いてあげればサンドボックスモードで DB を扱うことができます。

      setup do
        :ok = Ecto.Adapters.SQL.Sandbox.checkout(Repo)
      end

設定を共通化

テストファイルを増やすたびに alias やら setup をコピペするのは DRY ではないので、共通化して 1モジュールをインポートするだけでいいように変更します。

apps/us_core/test/test_helper.exs

  Ecto.Adapters.SQL.Sandbox.mode(UsCore.Repo, :manual)

+ {:ok, files} = File.ls("./test/support")
+
+ Enum.each files, fn(file) ->
+   Code.require_file "support/#{file}", __DIR__
+ end

  ExUnit.start()

apps/us_core/test/support/basic_settings_helper.exs

defmodule BasicSettingsHelper do
  defmacro __using__(_) do
    quote do
      use ExUnit.Case, async: true
      alias UsCore.Article
      alias UsCore.Repo

      setup do
        :ok = Ecto.Adapters.SQL.Sandbox.checkout(Repo)
      end
    end
  end
end

テストファイル作成

さて、本題のテストファイルを作ってみましょう。

apps/us_core/test/us_core/article_test.exs

defmodule UsCore.ArticleTest do
  use BasicSettingsHelper
  doctest UsCore.Article

  test "レコードを作れること" do
    %Article{
      title: "EMT",
      body: "エミリアたんマジ天使"
    } |> Repo.insert

    assert Article |> Repo.aggregate(:count, :id) == 1
  end
end

テスト実行

2回実行してみて、失敗したらサンドボックスモードの設定に失敗しているのかもしれません。

$ mix test
==> us_core

21:17:03.182 [debug] QUERY OK db=1.3ms
INSERT INTO `articles` (`body`,`title`,`created_at`,`updated_at`) VALUES (?,?,?,?) ["エミリアたんマジ天使", "EMT", {{2017, 9, 27}, {12, 17, 3, 163903}}, {{2017, 9, 27}, {12, 17, 3, 165464}}]

21:17:03.191 [debug] QUERY OK source="articles" db=1.8ms
SELECT count(a0.`id`) FROM `articles` AS a0 []
.

Finished in 0.07 seconds
1 test, 0 failures

Randomized with seed 106344

書き忘れていることがあるかもしれないので、もしテストに失敗するようなら教えていただけると嬉しいです。
今日は軽めの内容でしたがこれくらいで。