For browser automation and writing integration tests in Elixir.
Hound を使って Phoenix app の integration test を書きました。 ここで書いたコードは GitHub に push してあります。
mattsan/phoenix_integration_test_sample
プロジェクトを用意
Phoenix app のテストなので、Phoenix プロジェクトを用意します。 プロジェクト名はご自由に。
$ mix phx.new sample
$ cd sample
パッケージを追加する
Hound パッケージを追加します。
mix.exs
を編集して、hound
の行を追加します。テストでのみ利用するので only: :test
のオプションを指定しておきます。
{:phoenix_html, "~> 2.10"}, {:phoenix_live_reload, "~> 1.0", only: :dev}, {:gettext, "~> 0.11"}, - {:cowboy, "~> 1.0"} + {:cowboy, "~> 1.0"}, + {:hound, "~> 1.0", only: :test} ] end end
編集できたらHound パッケージを取得(ダウンロード)します。
$ mix deps.get
設定する
config/test.exs
を編集して Hound の設定を追加します。
テスト時にもサーバが起動するようにします。
config :sample, SampleWeb.Endpoint, http: [port: 4001], - server: false + server: true
ドライバを指定します。ここでは PhantomJS を利用する設定をしています。そのほかのドライバを指定するばあいはこちらを参照してください。
+config :hound, driver: "phantomjs"
test/test_helper.exs
を編集してテスト開始前に Hound が起動するようにします。
+Application.ensure_all_started(:hound)
ExUnit.start()
テストを書く
テストを書きます。今回は test/sample_web/
の下に intagration/
を作り、そこにテストファイルをおくようにしました。
例としてホームページのテスト test/sample_web/intagration/page_index_test.exs
を書きます。
use Hound.Helpers
を追加しますhound_session()
を追加します。この関数を記述しておくとセッションの管理を自動的に行ってくれますnavigate_to/2
でページをリクエストします。詳しくはドキュメントを参照してくださいfind_element/3
で要素を取得します。詳しくはドキュメントを参照してくださいinner_text/1
で要素のテキストを取得します。詳しくはドキュメント(ry
defmodule SampleWeb.PageIndexTest do use SampleWeb.ConnCase use Hound.Helpers hound_session() test "home", %{conn: conn} do navigate_to(page_path(conn, :index)) h2 = find_element(:tag, "h2") |> inner_text() assert h2 == "Welcome to Phoenix!" end end
テストを実行する…前に PhantomJS を起動しておく
PhantomJS を利用するので先に起動しておきます。このばあい、グローバルで実行できる状態でインストールされている必要があります(すぐ後でプロジェクトに含めておく方法を書きます)。 Remote WebDriver mode で利用するのでオプションで指定します。
$ phantomjs --wd
mix test
でテストを実行します。今回書いたテストだけを実行するばあいはファイル名を指定して実行します。
$ mix test test/sample_web/intagration/page_index_test.exs
PhantomJS をパッケージに追加する
PhantomJS はアプリケーションとは別に用意してもよいのですが、プロジェクトの中に閉じておきたいので assets に PhantomJS を追加してそれを利用するようにします。
assets/package.json
に PhantomJS を追加します。合わせてスクリプトを定義しておいて簡単に実行できるようにしておきます。
{ "repository": {}, "license": "MIT", "scripts": { "deploy": "brunch build --production", - "watch": "brunch watch --stdin" + "watch": "brunch watch --stdin", + "phantomjs": "./node_modules/phantomjs-prebuilt/bin/phantomjs --wd" }, "dependencies": { "phoenix": "file:../deps/phoenix", "phoenix_html": "file:../deps/phoenix_html" }, "devDependencies": { "babel-brunch": "6.1.1", "brunch": "2.10.9", "clean-css-brunch": "2.10.0", + "phantomjs-prebuilt": "^2.1.16", "uglify-js-brunch": "2.10.0" } }
インストールします。
$ cd assets
$ npm install
実行するには assets/
に移動して npm run
で起動します。
$ npm run phantomjs
PhantomJS をテスト実行時に自動的に起動する、そして終了時に停止する
PhantomJS を別途起動する必要がないように、テストヘルパに PhantomJS の起動と停止を書きます。 これで PhantomJS の起動停止を気にする必要がなくなりますが、
- テストのたびに起動のオーバーヘッドが発生する
- 複数のテストを同時には実行できない(それぞれが同じポートを利用しようとするので)
などのデメリットもあります。
test/test_helper.exs
を次のように編集します。
TestHelper. setup_phantomjs/0
で PhantomJS を起動します。そのなかでテスト終了時に kill コマンドを実行して PhantomJS のプロセスを停止するコードを System.at_exit/1
にかいておきます。
TestHelper.wait_starting/0
は、PhantomJS の起動が完了したときに標準出力に出力する文字列を待つ関数です。
テスト開始前に PhantomJS が起動するように TestHelper. setup_phantomjs/0
呼び出しを追加します。
defmodule TestHelper do @phantomjs_path "./assets/node_modules/phantomjs-prebuilt/bin/phantomjs --wd" def setup_phantomjs do port = Port.open({:spawn, @phantomjs_path}, [:binary]) {:os_pid, os_pid} = Port.info(port, :os_pid) System.at_exit(fn _ -> "kill #{os_pid}" |> String.to_charlist() |> :os.cmd() end) wait_starting() end def wait_starting do receive do {_port, {:data, output}} -> if !String.match?(output, ~r/running on port 8910/) do IO.puts "Starting PhatomJS failed: #{inspect output}" System.halt(1) end after 1_000 -> wait_starting() end end end TestHelper.setup_phantomjs() Application.ensure_all_started(:hound) ExUnit.start()
いつか読むはずっと読まない:もののけのみやつこ
初版が発売されたとき、友人と散々プレイしたカードゲーム。
今年は初版発売から 30 年だそうです。

- 出版社/メーカー: アークライト
- 発売日: 2018/01/13
- メディア: おもちゃ&ホビー
- この商品を含むブログを見る