Vagrant環境下におけるブラウザテストについて(Chrome編)
ユニットテストなどは当たり前に行われるようになっていますが、Webブラウザベースのテスト(いわゆる結合、機能テスト)はつい後に放っておかれがちです。UIは頻繁に変わるケースがあり、それがシステムと関係のない部分であってもテストが落ちる可能性があるため、一旦落ち着くまではそのままになり、いつしかテストが行われなくなったりします。
もちろんそのままで良いわけではなく、実際のユーザが使っている環境下でこそ正しく動いているか確認できなければなりません。そのためのツールとしてよく知られているのがSelenium + WebDriverでしょう。
現在の開発、テスト環境
クライアントPCの性能が向上するのに合わせてクライアントPC上に開発用のWebサーバを立ててその場で実行結果を確認する開発方法が当たり前になっています。さらにWindowsユーザの場合、開発環境と本番環境が異なるケースが多く(サーバがLinuxディストリビューションなど)VMWare Playerなどを使ってサーバOSの仮想環境を作って開発するのもよく行われてきました。
そんな中、最近ではVagrantを使ってVirtualBoxベースの仮想環境で開発を行うことが増えてきました。Vagrantを使った場合、Vagrantfileの配布だけで開発用サーバ環境が整ってしまうのがポイントです(もちろんVagrantのインストール、加えてVirtualBoxが必要ですが)。しかしこのようなケースにおいてSeleniumでどうテストを行うかといった情報があまり多くないようです。
従来はこのように一つのPC環境にWebブラウザ、Webサーバが入っています。つまりlocalhostでアクセスできる状態です。

それがVagrantによって環境が分離しています。さらに最近ではスマートフォン、タブレットのWebテストを行いたいというニーズも多いです。

次回以降詳しく書きますが、iOSの場合はMac OSX向けにシミュレータがあります。シミュレータは実行環境を模擬的に再現しています。外部から見た振る舞いを模倣しているだけです。つまりiOSシミュレータのSafariで http://localhost/ にアクセスすると、それは母艦にアクセスするのと同じことになります。
対してエミュレータはハードウェアレベルで再現しています。そのため、Androidエミュレータで http://localhost/ にアクセスすると、それはAndroidエミュレータ本体のWebサーバにアクセスするということになります。つまりAndroidエミュレータでテストする場合はVagrat – 母艦 – Androidエミュレータの3つの環境を橋渡ししなければなりません。Androidのテストについては次回説明します。
Google Chromeでのテスト
今回は分かりやすいところでGoogle Chromeを使ってテストを行います。WebアプリケーションはRuby on Railsを使っています。今回の目的にあったVagrantfileがrails/rails-dev-boxに公開されています。これをcloneして開発環境を整えます。

$ git clone https://github.com/rails/rails-dev-box.git
$ cd rails-dev-box
$ vagrant up
: しばらくかかります
$ vagrant ssh
$ cd /vagrant
$ rails new web -T # Rspecベースなのでテストを除外します。もしかすると sudo gem install rails が必要かも知れません。
$ cd web
このVagrantfileを見ると分かりますが、仮想環境側の3000番ポートがそのまま母艦の3000番ポートにつながっています。そのため母艦の http://localhost:3000/ にアクセスすると、仮想環境の http://localhost:3000/ にアクセスしたのと同じになります。また、 /vagrant がカレントディレクトリになりますので、そこにRailsアプリケーションを作成して母艦からファイル操作ができるようになっています。
必要なライブラリは以下の通りです。Gemfile に記載します。
gem 'rspec-rails'
gem 'capybara'
gem 'selenium-webdriver'
これらのインストール( bundle install && rails generate rspec:install)ができたら、 spec/support/capybara_drivers.rb
を作成します。ここにはWebブラウザごとの設定を記述します。
Capybara.javascript_driver = ENV['DRIVER'] ? ENV['DRIVER'].to_sym : :chrome
Capybara.app_host = [:safari, :chrome, :firefox, :iphone, :ipad].include?(Capybara.javascript_driver) ? "http://localhost:3000" : "http://192.168.100.116:3000"
Capybara.default_wait_time = 10
Capybara.run_server = false
Capybara.register_driver :chrome do |app|
Capybara::Selenium::Driver.new app,
browser: :remote,
desired_capabilities: Selenium::WebDriver::Remote::Capabilities.chrome,
url: "http://192.168.100.116:4444/wd/hub"
end
IPアドレス(192.168.100.116)はそれぞれ読み替えてください。4444番ポートはそのままで大丈夫です。
ここで注意して欲しいのは、 app_host と run_server です。app_hostは一度設定すると Capybara.register_driver
のブロック内で上書きしても変更されないようです。そのため、テスト対象のブラウザによって見る場所を変えています。192.168.100.でアクセスするのはAndroidエミュレータまたは実機になります。
Capybara.run_serverのフラグを落としておかないと Androidエミュレータでのテストができませんでした(筆者はこれに1日ハマったのでご注意ください)。Selenium Serverへのアクセスがいかない場合はここが原因かも知れません。
テストのファイルは spec/features/ 以下に書きます。たとえば以下のようになります。
#spec/features/hello_spec.rb
require 'spec_helper'
describe "Web Test", type: :feature, js: true do
it "Access to root" do
visit "/"
page.should have_content("Home")
sleep(2)
end
end
sleepを2秒入れているのはテストが終わった瞬間にWebブラウザが閉じてしまうので確認用としてです。Rspecの書き方として has_content?もあるのですが、これは true/falseを返すのでpage.shouldに対しては使えないようです。ご注意ください。
この例を見て分かる通り、 http://localhost:3000/ にアクセスすると Homeという文字を出すだけです。そのチェックをしています。テストに備えてサーバを起動します。
$ rails s
=> Booting WEBrick
=> Rails 4.1.6 application starting in development on http://0.0.0.0:3000
=> Run `rails server -h` for more startup options
=> Notice: server is listening on all interfaces (0.0.0.0). Consider using 127.0.0.1 (--binding option)
=> Ctrl-C to shutdown server
[2014-10-29 07:35:39] INFO WEBrick 1.3.1
[2014-10-29 07:35:39] INFO ruby 2.1.3 (2014-09-19) [i386-linux-gnu]
[2014-10-29 07:35:39] INFO WEBrick::HTTPServer#start: pid=4076 port=3000
母艦の環境を整える
Google Chromeの場合はさほど難しくありません。Selenium Serverを公式サイトからダウンロードします。Google Chromeは必要なのでダウンロード、インストールしてください。
ダウンロードしたらSelenium Serverを起動します。
$ java -jar selenium-server-standalone-2.43.1.jar
16:33:42.764 INFO - Launching a standalone server
16:33:42.825 INFO - Java: Oracle Corporation 24.60-b09
16:33:42.825 INFO - OS: Mac OS X 10.10 x86_64
16:33:42.853 INFO - v2.43.1, with Core v2.43.1. Built from revision 5163bce
16:33:42.960 INFO - Default driver org.openqa.selenium.ie.InternetExplorerDriver registration is skipped: registration capabilities Capabilities [{platform=WINDOWS, ensureCleanSession=true, browserName=internet explorer, version=}] does not match with current platform: MAC
16:33:43.042 INFO - RemoteWebDriver instances should connect to: http://127.0.0.1:4444/wd/hub
16:33:43.043 INFO - Version Jetty/5.1.x
16:33:43.045 INFO - Started HttpContext[/selenium-server/driver,/selenium-server/driver]
16:33:43.046 INFO - Started HttpContext[/selenium-server,/selenium-server]
16:33:43.046 INFO - Started HttpContext[/,/]
16:33:43.095 INFO - Started org.openqa.jetty.jetty.servlet.ServletHandler@59bf8a16
16:33:43.096 INFO - Started HttpContext[/wd,/wd]
16:33:43.114 INFO - Started SocketListener on 0.0.0.0:4444
16:33:43.114 INFO - Started org.openqa.jetty.jetty.Server@70eae613
このように起動して4444ポートで待ちの状態になります。
テストの実行
テストは仮想環境側で行います。つまり母艦側にはRuby/Ruby on Railsの環境は不要ということです。
$ /usr/bin/ruby2.1 -S rspec ./spec/features/hello_spec.rb
.
Finished in 7.97 seconds
1 example, 0 failures
Randomized with seed 61665

このように 仮想環境から母艦側のSelenium Serverを呼び出して、母艦のGoogle Chromeから仮想環境のWebアプリケーションをテストできるようになります。ざっくりと図にするとこのようになります。

SafariやFirefoxの場合、ほぼ同じ設定でいけます。
# Safariの場合
Capybara.register_driver :safari do |app|
Capybara::Selenium::Driver.new app,
browser: :remote,
desired_capabilities: Selenium::WebDriver::Remote::Capabilities.safari,
url: "http://192.168.100.116:4444/wd/hub"
end
# Firefoxの場合
Capybara.register_driver :firefox do |app|
Capybara::Selenium::Driver.new app,
browser: :remote,
desired_capabilities: Selenium::WebDriver::Remote::Capabilities.firefox,
url: "http://192.168.100.116:4444/wd/hub"
end
browser: :remote
の設定が肝になります。
まとめ
最も大きな利点として、母艦(WindowsやMac OSX)であればGUIなのでWebブラウザを簡単に用意できるということです。たとえばLinuxサーバ上でテストしようと思った場合、PhantomJSやQtを使ったWebブラウザを用意しなければなりません。これは本来本番環境には不要なものですし、Qtをインストールするのはサイズが大きかったりします。Vagrantを使った仮想環境でもそれは同じです。また、それを行った場合でもテストはFirefox、Google Chromeまでで、その他のIEやiOS、Androidでのテストはできないでしょう。
母艦側のGUI画面でWebブラウザを実行するのは、よりユーザの環境に近いところでテストができるということです。かといって母艦側に開発環境を整えると、プロジェクトごとに必要なライブラリバージョンが違ったり、実行環境を整備するのは大変です。Vagrantを使えばすぐに同じ環境が実現できます。
次回は iOSシミュレータ、Androidエミュレータでのテスト方法についてご紹介します。ハマりどころが多いのでお役立てください。
Trackbacks & Pingbacks
コメントは受け付けていません。