[Elixir]concurrent integration test with Hound and handle it with tag

雑にしか書きませんが、Phoenixのcontrollerのテストでは、あるURLへの操作に対する結果のチェックにはstatus codeが何か、そのtitle要素は何かといった簡単なHTML要素をみます。そこは静的な要素をチェックできるのですが、画面の遷移が絡んでくるとintegration testと呼ばれる段階のテストを用意する必要があります。

Elixirでは、その手のツールに以下の2つがあります。

Wallabyのほうが後発です。これはconcurrentなテストを主眼に開発されているようです。ただ、対応ブラウザがPhantomJSだけだったので、私はHoundを選びました。

そして、concurrent integration testを行うにはphoenix_ecto3.0 + Ecto 2.0を使う必要があります。これは、Ecto2.0から入ったownership制のsandbox環境を使い、concurrentなテストを実行する必要があるためです。
※Ectoのこのownership制の話とか気になる人はこちらを読むと良いと思います。コード

設定

以下の設定説明を参考にすると、基本的なところは完了。サクッと実行できます。なのでここではリンクだけ…

私はfirefoxとWebDriverのstandaloneを使ってサクッと実行しました。
WebDriverはこちらからダウンドード可能です=> https://selenium-release.storage.googleapis.com/index.html

tips

通常、この手のintegration testはブラウザを使うのでテスト実行が遅かったり不安定だったりします。そのため、その他のmodelやcontrollerのテストとは別に制御できるようにして、不要なときはskipするなりしたいです。

ここでは、tagを使って制御しましょう。ただ、よくあるメソッドごとに @tag をつけるのでは煩雑になるいっぽうなので、 integration_case.ex なんかを作って、それを読み込んだ全てのモジュールに対して勝手にtagがつくようなやり方です。

tagを付与する

  • support/integration_case.ex にtagを設定する
    • 以下のようにヘルパーを作ってあげると、 use MyApp.IntegrationCase したモジュールは自動的に @moduletag :integration のtagが付与されます。


defmodule MyApp.IntegrationCase do
use ExUnit.CaseTemplate
using do
quote do
use Hound.Helpers
import Ecto
import Ecto.Changeset
import Ecto.Query
import MyApp.Router.Helpers
alias MyApp.Repo
# The default endpoint for testing
@endpoint MyApp.Endpoint
# run tests only "integration" mode
@moduletag :integration
end
end
setup tags do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(MyApp.Repo)
unless tags[:async] do
Ecto.Adapters.SQL.Sandbox.mode(MyApp.Repo, {:shared, self()})
end
metadata = Phoenix.Ecto.SQL.Sandbox.metadata_for(MyApp.Repo, self())
Hound.start_session(metadata: metadata)
:ok
end
end

通常の mix test ではintegration tagを無視して実行する

  • test/test_helper.exs を以下のようにする
ExUnit.configure exclude: [integration: true]
ExUnit.start

この設定を終えた段階で、 mix test とやると、 integration tag がついているモジュールに含まれるテストケースはすべてskipされます。

integration を実行したい

無視されるばかりではなく、integrationだけを実行してみます。

  • integration tagだけ
    • mix test --only integration
  • integration tag含めたすべて
    • mix test --include integration:true

締め

私がプライベート、社内プロダクトで試している限りでは、今の所すべてのテスト(model/controller/integration)は async: true で実行していますが安定してテスト実行されています。

Ecto2.0からのownership制によるDBへのsession制御、賢いですね。ただ、確かあればPostgreSQLはちゃんと動くのですが、MySQLはdeadlockが発生することがあるとか…

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.