Edited at

Phoenixでインテグレーションテストをする

More than 3 years have passed since last update.


やりたいこと/やること

Elixir/PhoenixでSessionを使用した画面遷移を伴うインテグレーションテストをしたい

PhoenixデフォルトではSessionを扱ったテストを書くのが少し面倒なようなので、今回はインテグレーションテスト用のライブラリでPhantomJS経由でテストをします

ここらへん公式でドキュメントもっと充実するかデフォルトで簡単にインテグレーションテスト出来るといいのになー


環境



  • Phoenix 1.1.4

  • Elixir 1.2.5

  • hound 1.0.0

  • PhantomJS 2.1.1

  • Docker 1.11.1


手順


  • ElixirのIntegration Testライブラリのhoundをmixの依存に追加

mix.exs

{:hound, "~> 1.0"}

依存を更新

mix deps.get


  • ローカルにPhantomJSを入れるのが面倒なのでリモートサーバとしてPhantomJSをDockerで起動する

docker run -itd -p 8910:8910 shufo/phantomjs --webdriver 8910

docker-composeを使っているならサービスをdocker-compose.ymlに追加する

  phantomjs:

image: shufo/phantomjs
container_name: phantomjs
hostname: phantomjs
command: "--webdriver 8910"



  • houndの設定

config/config.ex

config :hound, driver: "phantomjs", host: "phantomjs", port: 8910

補足: hostは起動したphantomjsのホスト名。docker-composeで起動した場合は自動的にservice名で解決出来るのでphantomjsでok。docker-composeを使わない場合はDockerデーモンを起動しているマシンのホスト名かdocker inspect等でコンテナのIPを確認。

test_helpers.exs

Application.ensure_all_started(:hound)

ExUnit.start

ExUnit.startの前にApplication.ensure_all_started(:hound)を追加

config/test.exs

config :example, Example.Endpoint,

http: [port: 4001],
- server: false
+ server: true

MIX_ENV=test時のEndpointのconfigをserver: trueに変更


  • Testを書く

test/controllers/auth_controller_test.exs

defmodule Example.AuthControllerTest do

use Example.ConnCase
import Example.Router.Helpers
use Hound.Helpers

# Start hound session and destroy when tests are run
hound_session

@moduletag :auth

setup do
# ユーザ作成処理等
# ~中略~

navigate_to("/auth/login")
assert page_source =~ "ログイン"

username = "foobar"
find_element(:name, "username")
|> fill_field(username)

find_element(:name, "password")
|> fill_field("123456")

find_element(:tag, "button")
|> click

assert page_source =~ "ようこそ"
{:ok, username: username}
end

test "user can logout", %{username: username} do
# click logout
find_element(:id, "button_get_logout")
|> click
# Assert redirected to login page
assert page_source =~ "ログイン"
assert current_path == auth_path(conn, :get_login)
# Assert logouted user can't access to private page
navigate_to("/mypage")
assert current_path == auth_path(conn, :get_login)
end
end

補足: setup内で共通処理をしてログイン。HoundのHelperのfind_element/2で要素を選んで値を入れたり出来る。


  • Test実行

mix test --only auth

@moduletagでテストの実行範囲を絞れる

これで一通りインテグレーションテストが出来た。

find_element/2で指定できるelementの指定の方法は他にも:name, :tag, :id, :class, :css, :link_text等がある。

fill_element/2で選択した要素にinput valueを入れてclick/1submit/1でフォームをsubmitしてcurrent_path/0current_url/0で遷移先のパスが正しいか確認。あとpage_source/0でページに期待する文字列が含まれるかチェック、辺りが出来るので基本的なところは十分だと思うけど足りない場合は Hexのdocument を参照してください。


追記:

少しやり方が特殊なテストでハマったので追記


  • ファイルアップロード

input_into_field/2に対してファイルのフルパスを入力する

find_element(:name, "image")

|> input_into_field("#{__DIR__}/../../fixtures/example.jpg")

ファイルはphantomjsが実行されている環境のローカルファイルシステムを参照するのでDockerで起動している場合はコンテナに必要なファイルをマウントしておく

例)

docker run -itd -p 8910:8910 -v $(pwd):/app shufo/phantomjs --webdriver 8910

  phantomjs:

image: shufo/phantomjs
container_name: phantomjs
hostname: phantomjs
command: "--webdriver 8910"
+ volumes:
+ - ".:/app"

カレントディレクトリを/appにマウントするのでinput_into_fieldでは/app/test/fixtures/example.jpgなどで参照出来る


  • セレクトボックスの選択

find_element(:css, "#element_id option[value='value']")

|> click