[Elixir]Plug.Testを使ったRequestのテスト

作業メモ。

  • Elixir 1.0.5
  • Phoenix 0.14.0

Plug.Testを使ったやつ

テスト対象

defmodule MyPlug do
  import Plug.Conn

  def init(options) do
    options
  end

  def call(conn, _opts) do
    conn
    |> put_resp_content_type("text/plain")
    |> send_resp(200, "Hello world")
  end
end

テストコード

defmodule MyPlugTest do
  use ExUnit.Case, async: true
  use Plug.Test

  @opts MyPlug.init([])

  test "return hello world" do
    conn = conn(:get, "/") # コネクションを定義
    conn = MyPlug.call(conn, @opts) # コネクションをはる

    assert conn.state == :sent
    assert conn.status == 200
    assert conn.resp_body == "Hello world"
  end
end

Phoenixを使ったやつ

test_helper.exs で、test用DBのcreate、migrationを行っているのですね。

test/test_helper.exs

ExUnit.start

# Create the database, run migrations, and start the test transaction.
Mix.Task.run "ecto.create", ["--quiet"]
Mix.Task.run "ecto.migrate", ["--quiet"]
Ecto.Adapters.SQL.begin_test_transaction(HelloPhoenix.Repo)

ファイル単位とか、以下のように行単位でテストできるのですね。

$ mix test test/views/error_view_test.exs:12

タグの付与と実行

moduleへのタグ

  • moduleへのタグ定義
defmodule HelloPhoenix.ErrorViewTest do
  use HelloPhoenix.ConnCase, async: true

  @moduletag :error_view_case
  • 実行
$ mix test --only error_view_case
  • 実行
$ mix test --only error_view_case:true # 成功する
$ mix test --only error_view_case:false # 失敗する。falseを付与したものが存在しないため。
  • 特定のタグのみ除いたテストケースの実行
$mix test --exclude error_view_case

test case個別へのタグ

  • タグの定義
defmodule HelloPhoenix.ErrorViewTest do
  use HelloPhoenix.ConnCase, async: true

  @moduletag :error_view_case

  import Phoenix.View

  @tag individual_test: "yup"
  test "renders 404.html" do
    assert render_to_string(HelloPhoenix.ErrorView, "404.html", []) ==
           "Page not found"
  end

  @tag individual_test: "nope"
  test "render 500.html" do
    assert render_to_string(HelloPhoenix.ErrorView, "500.html", []) ==
           "Server internal error"
  end
  • 実行
$ mix test --only individual_test
$  mix test --only individual_test:yup # タグをより細かく。
$  mix test --only individual_test: nope # タグをより細かく。
  • 特定のmoduleを除いたうえで、individual_test:yupを実行する
$ mix test --exclude error_view_case --include individual_test:yup

ランダムにテストを実施する

$ mix test --seed 20150712

これ、面白いなーと感じました。 🙂

テストの自動生成

以下のようにcontroller、modelを作成したら、テストケースも自動生成されていました。
作成したモデルに対する、基本的なテストケースの自動生成良いですね。
ざっと生成されたテストケース見てみると、moduleで作成したリソースの生成/更新などの基本的な正常系、作成失敗などのエラー系。

ちなみに、以下を実行した後だと、 phoenix.gen.html とうViewも自動生成されるので、かなりお手軽。

$ mix phoenix.gen.html User users name:string email:string bio:string number_of_pets:integer

test/controllers/user_controller_test.exs

defmodule HelloPhoenix.UserControllerTest do
  use HelloPhoenix.ConnCase

  alias HelloPhoenix.User
  @valid_attrs %{bio: "some content", email: "some content", name: "some content", number_of_pets: 42}
  @invalid_attrs %{}

  setup do
    conn = conn()
    {:ok, conn: conn}
  end

  test "lists all entries on index", %{conn: conn} do
    conn = get conn, user_path(conn, :index)
    assert html_response(conn, 200) =~ "Listing users"
  end

  test "renders form for new resources", %{conn: conn} do
    conn = get conn, user_path(conn, :new)
    assert html_response(conn, 200) =~ "New user"
  end

  test "creates resource and redirects when data is valid", %{conn: conn} do
    conn = post conn, user_path(conn, :create), user: @valid_attrs
    assert redirected_to(conn) == user_path(conn, :index)
    assert Repo.get_by(User, @valid_attrs)
  end

  test "does not create resource and renders errors when data is invalid", %{conn: conn} do
    conn = post conn, user_path(conn, :create), user: @invalid_attrs
    assert html_response(conn, 200) =~ "New user"
  end

  test "shows chosen resource", %{conn: conn} do
    user = Repo.insert! %User{}
    conn = get conn, user_path(conn, :show, user)
    assert html_response(conn, 200) =~ "Show user"
  end

  test "renders page not found when id is nonexistent", %{conn: conn} do
    assert_raise Ecto.NoResultsError, fn ->
      get conn, user_path(conn, :show, -1)
    end
  end

  test "renders form for editing chosen resource", %{conn: conn} do
    user = Repo.insert! %User{}
    conn = get conn, user_path(conn, :edit, user)
    assert html_response(conn, 200) =~ "Edit user"
  end

  test "updates chosen resource and redirects when data is valid", %{conn: conn} do
    user = Repo.insert! %User{}
    conn = put conn, user_path(conn, :update, user), user: @valid_attrs
    assert redirected_to(conn) == user_path(conn, :index)
    assert Repo.get_by(User, @valid_attrs)
  end

  test "does not update chosen resource and renders errors when data is invalid", %{conn: conn} do
    user = Repo.insert! %User{}
    conn = put conn, user_path(conn, :update, user), user: @invalid_attrs
    assert html_response(conn, 200) =~ "Edit user"
  end

  test "deletes chosen resource", %{conn: conn} do
    user = Repo.insert! %User{}
    conn = delete conn, user_path(conn, :delete, user)
    assert redirected_to(conn) == user_path(conn, :index)
    refute Repo.get(User, user.id)
  end
end

test/models/user_test.exs

defmodule HelloPhoenix.UserTest do
  use HelloPhoenix.ModelCase

  alias HelloPhoenix.User

  @valid_attrs %{bio: "some content", email: "some content", name: "some content", number_of_pets: 42}
  @invalid_attrs %{}

  test "changeset with valid attributes" do
    changeset = User.changeset(%User{}, @valid_attrs)
    assert changeset.valid?
  end

  test "changeset with invalid attributes" do
    changeset = User.changeset(%User{}, @invalid_attrs)
    refute changeset.valid?
  end
end

HelloPhoenix.ModelCase は、 test/support/model_case.ex で実装されている。

コメントを残す

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

WordPress.com ロゴ

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

Twitter 画像

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

Facebook の写真

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

Google+ フォト

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

%s と連携中