やりたいこと/やること
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/1
かsubmit/1
でフォームをsubmitしてcurrent_path/0
かcurrent_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