読者です 読者をやめる 読者になる 読者になる

capybara-webkitを使ってインテグレーションテストする方法を探す

弊社でもAjax的なプログラミングを少しずつ始めていまして、ちゃんとインテグレーションテストする方法が欲しくなってきたところでした。で、いろいろ見てみると、capybara-webkitとか言うのが良さそう。

でも、ちゃんとテストできるまで、なんか妙に苦労したのでその話をします。あと基本的には、例によってCapybaraのREADMEを隅から隅まで読めば全部書いてあるので、ちゃんと読んだほうが良いかもしれません。

ぼくのかんがえたさいきょうのtest_helper

Capybara.default_driver = :rack_test

class ActionDispatch::IntegrationTest
  include Capybara::DSL

  self.use_transactional_fixtures = true
    
  def self.test_with_js
    self.use_transactional_fixtures = false
    
    setup do
      Capybara.current_driver = :webkit
      
      DatabaseCleaner.strategy = :truncation
      DatabaseCleaner.start
    end
    
    teardown do
      DatabaseCleaner.clean
      Capybara.use_default_driver
    end
  end

  setup do
    Capybara.reset_sessions!
    # 適当に初期化する
  end

  teardown do
    # 適当に掃除する
  end
end

JSが必要なインテグレーションテストをするときはtest_with_jsを呼んでおく。全部webkitでやるとすごい遅いよ!特定のテストだけやる方法もあると思うけど、まあいいや。

class HelloHelloTest < ActionDispatch::IntegrationTest
  self.test_with_ajax
  
  test "JS is enabled" do
    assert_equal 3, page.evaluate_script("1+2")
  end
end

いちおうGemfileも書いておこう。

gem 'capybara'
gem 'capybara-webkit', :git => "git://github.com/thoughtbot/capybara-webkit.git"
gem 'database_cleaner'

最初はAkephalosを使おうとした

なんか文字化けするので止めた。あと、Capybaraの新しいやつとうまく動かない気配があったので。

ただ、良く考えてみると、Gemfileに:git => ...と書く方法を試していないので、新しいバージョンだといろいろ良かったのかもしれない。まあめんどくさいしいいや。

DBがからっぽになる問題

まず、適当にintegration testの中からモデルを触っているとぶつかるのがこの問題だと思う。

:webkitとか:akephalosとか、とにかく:rack_test以外のドライバを使うときは、Webサーバが別のスレッドで動くので、トランザクション?とかの関係でこうなる。

class ActionDispatch::IntegrationTest
  self.use_transactional_fixtures = false
end

すると良い。また、DatabaseCleanerを使ってリセットするのが常套手段のようなので、それも設定しておく。

:remote => trueななんかをしてから処理が終わる前に次にいっちゃう問題

Capybaraのほうでうまいことやってくれてるらしいんだけど、微妙に制限がある。

def assert_list_are(list)
  assert_equal list, all("#list li").map(&:text)
end

とかやってたらうまくいかなかった。findを使うと待つよ!と書いてあったので、

def assert_list_are(list)
  messages = list.map.with_index {|message, index| find("#list li:nth-child(#{index+1})").text }
  assert_equal list, messages
end

こんな感じにしたら、とりあえずうまく動いてた。

:webkit使うとうまくいかないテストがあった

なんでだかよくわからないんだけど、visitしたあとに返ってこない系で、しびれを切らしてCtrl-Cするやつがあった。全部webkitでやらないのは、それも理由。

ただし正直なところまだあんまりわかってない

かんたんなプロジェクトを作っていろいろ試行錯誤した。

本物のプロジェクト(つまりユビレジのことだけど)では、とりあえずevaluate_scriptが動くことだけ確認してあって、実際にAjaxのテストはまだやってない。

どうでも良いけど、websocketのテストとかどうするんだろうな。専用の環境を作ればなんとかなるんだろうか。