Request SpecでJavascriptのあるページをテストする方法、 Capybara + Selenium, Capybara + Akephalos など

先日リリースした 萌えトーク ではEnd-to-Endテストには Request Spec + Capybara を使っていますが、Javascriptの部分は適当なヘルパーメソッドを使いJavascriptを動作させずにテストしましたが、Capybara のドライバーを selenium や Akephalos (HTMLUnit)に入れ替える事で実際にJavascriptを動かして End-to-Endテスト を行う事が出来ます。


写真は、World's Largest Rodent Born at San Diego Zoo! - ZooBorns より

テスト対象

Scaffoldが作った一覧ページに、jQuery を使いShowをクリックした場合showページに遷移せず、一覧画面の下の方の

にTodo内容を表示さいます。

  • app/view/index.html.erb
<h1>Listing todos</h1>

<table>
  <tr>
    <th>Due</th>
    <th>Task</th>
    <th></th>
    <th></th>
    <th></th>
  </tr>

<% @todos.each_with_index do |todo, ix| %>
  <tr>
    <td><%= todo.due %></td>
    <td><%= todo.task %></td>
    <td><%= link_to 'Show', todo, :class=>'show_detail', :remote => true %></td>
    <td><%= link_to 'Edit', edit_todo_path(todo) %></td>
    <td><%= link_to 'Destroy', todo, :confirm => 'Are you sure?', :method => :delete %></td>
  </tr>
<% end %>
</table>

<br />
<%= link_to 'New Todo', new_todo_path %>

<div id="detail_area" style="margin-top:20px; border:solid 1px; width:200px">
  詳細
</div>

<%= javascript_tag do %>
$(".show_detail").bind("ajax:success", function(data, statusHtml, xhr) {
  $("#detail_area").html(statusHtml);
});
<% end %>
  • app/controllers/todos_controller.rb

コントローラーの showメソッドは layout を使わないようにします。

  def show
    @todo = Todo.find(params[:id])

    respond_to do |format|
      format.html { render :layout => false}
      format.xml  { render :xml => @todo }
    end
  end
  • app/views/layouts/application.html.erb

layout には、もちろん jQuery を指定します。

<!DOCTYPE html>
<html>
<head>
  <title>Todo3</title>
  <%= stylesheet_link_tag :all %>
  <%= javascript_include_tag "jquery.min", "rails" %>
  <%= csrf_meta_tag %>
</head>
<body>

<%= yield %>

</body>
</html>

動かすと以下のようになります。

Selenium

CapybaraにはSelenium用のドライバーが内蔵されていて、設定を変更するだけで Selenium を使ってテストを行えます。ご存知のようにSelenuium は実際のブラウザー(デフォルトはFirefox)を起動しブラウザー上でテストが実行されますので、テストには時間が掛かります。

  • spec/requests/show_feature_spec.rb

テストは以下の様に、表示エリア div#detail_area にTodo表示した文字列が在るかを検証しています。
ここで、describe に :js => true とオプションが指定されているのはこのテストは Javascript が使われている事をあらわしていて、このオプションがないテストは通常の rack_test で実行されます。

require 'spec_helper'

describe "Todo詳細の表示", :js => true do
  fixtures :todos

  it "showをクリックするとlistページ下部に詳細がが表示できる" do

    visit list_page
    page.find("table tr:eq(2) a:eq(1)").click
    
    page.should have_css "#detail_area", :text=>"2011-02-18"
    page.should have_css "#detail_area", :text=>"打ち合わせ"
  end
end
  • spec/spec_helper.rb

上で書いた :js => true を有効にしているのは spec_helper.rb に書いた以下の設定です。この設定で :js => true のあるテストの前にはテストを行うドライバーを Selenium に切替、終了したらデフォルト(rack_test)に戻しています。

  。。。
RSpec.configure do |config|
  。。。
  config.before(:all, :js => true) do
    Capybara.current_driver = :selenium
  end
  config.after(:all, :js => true) do
    Capybara.use_default_driver
  end
  。。。
end

Akephalos

Seleniumを使ったテストは実際のブラウザーを使うので、テストとして完璧ですが時間がかかる、画面のない(Xを起動してないLinux等)サーバー等では実行できません(何か手があるのかな?)。
Akephalos は Java製のWebアプリテスト用のフレームワーク HTMLUnitJavaで実装されたJavascriptインタプリタRhino を使いJavascriptを含むテストを行える Capybara用ドライバーです。 HTMLUnitRhinoJavaで書かれていますが、それらとはDrbを使い通信しているようです。

テストのコード spec/requests/show_feature_spec.rb はselenuim と同じですが、akephalos のインストールとドライバーを :akephalos にする必要があります。

  • Gemfile
group :test, :development do
  gem "rspec-rails", ">= 2.5.0"
  gem 'email_spec'
  gem 'capybara'
  gem 'spork'
  gem 'akephalos'
end
  • spec/spec_helper.rb
require 'akephalos'

  。。。
RSpec.configure do |config|
  。。。
  config.before(:all, :js => true) do
    Capybara.current_driver = :akephalos
  end
  config.after(:all, :js => true) do
    Capybara.use_default_driver
  end
  。。。
end

Akephalos によるテストは javaHTMLUnit/Rhinoの起動に時間がかかり、今回のサンプルでは Selenium より時間がかかってしまいますが、 HTMLUnit/Rhinoが起動してしまえばテスト自体は Selenuim より早いようです。
Cucumber+Capybara+akephalosを使ってみた - ryog on rails にCucumber + Selenium と Cucumber + Akephalos の実行時間の比較があります。

env.js

CapybaraでJavascriptが動かせ MRI(CRuby) で使えるものとして env.js という Rhino+JavaScript+Rubyのドライバーがありますが、今回のサンプルでは動きませんでした。 また Safari/Chromeのエンジン WebKitを使った capybara-webkit などもあるようです。このへんはこれからが楽しみですね!



今回も WEB+DB PRESS Vol.61の 「Rails 3テスト最前線」がたいへん役にたちました。もちろん jnicklas/capybara - GitHub も。

WEB+DB PRESS Vol.61

WEB+DB PRESS Vol.61