Nexus6 買っちゃいました。何やってんだ自分とちょっと思わなくはないですが、まぁちょっと早いクリスマスプレゼント(自分への)ってことで。
そんなことはどうでも良いのですが、最近現場でも、画面の複雑さが増すに従ってデグレが発生する頻度が上がるようになってきました。
客先としても、「デグレなんとかなんない?」と言われたので、とりあえず「時間といいマシンください」とは言いましたが、それだけじゃ足りないので、Seleniumの導入を行いたいです。
が、Seleniumを単純に導入すると言っても、環境の用意がまず大変です。
- テスト環境と別の環境を用意する?
- データはどうやって投入する?
- Windows機は使うのか?
とかとか色々ありますが、とりあえず動き出さないとならなさそうになったところで、こんな記事を見かけました。
http://gongo.hatenablog.com/entry/2014/12/02/002148
Docker の中で Selenium hubを動作させる、というやり方をすれば、必要最小限の労力でFirefoxとか確認ができるってことですね。これっきゃないかな、と思いましたが、いきなり実践投入はあれなので、ちょっとVagrant上で試してみました
簡単な構成
Host -> Vagrant -> Guest -> Docker -> Selenium hub + slaves
こんな感じです。間がかなり挟まっているので、パフォーマンスにはあまり期待しないでおきます。
Vagrantfile の設定
Docker についての設定とかは前述のページをまるぱく・・・ゲフンゲフン、参考にさせていただくとして、Vagrantの設定が必要ですんで、 vagrant init
したところで記述していきましょう。
ちなみに今回はゲストとしてUbuntu 14.04を使いました。ここで別に辛いものを利用する必要もないので。
Vagrantfileはこんな感じになりました。
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "ubuntu/trusty64"
# ホストオンリーネットワークを使わない場合はこっちの設定も必要
# config.vm.network "forwarded_port", guest: 4444, host: 4444
# Create a private network, which allows host-only access to the machine
# using a specific IP.
config.vm.network "private_network", ip: "192.168.33.10"
# Create a public network, which generally matched to bridged network.
# Bridged networks make the machine appear as another physical device on
# your network.
# config.vm.network "public_network"
# If true, then any SSH connections made will enable agent forwarding.
# Default value: false
# config.ssh.forward_agent = true
# Share an additional folder to the guest VM. The first argument is
# the path on the host to the actual folder. The second argument is
# the path on the guest to mount the folder. And the optional third
# argument is a set of non-required options.
# config.vm.synced_folder "../data", "/vagrant_data"
config.vm.provider "virtualbox" do |vb|
vb.customize ["modifyvm", :id, "--memory", "2048", "--cpus", "2", "--ioapic", "on"]
end
config.vm.provision "shell", path: "provision.sh"
end
若干ポイントとしては、あえてホストオンリーネットワークを定義しておくことで、localhost上のポートと被る心配を減らしています。Docker上にSelenium hubを構築する関係上、Docker上にコンテナが配置されて初めてポートが決定されるので、ホストオンリーネットワークの方が多分楽です。
また、内部で(とりあえず)5ノード起動するので、メモリとCPUはある程度多めにしておきました。ノードが一個とかなら、多分1GBくらいで大丈夫です。
provisioning の設定
provision.shでは、Docker本体と fig というツールをインストールします。最近はこういったプロビジョニングはAnsibleで書くのが好みですが、今回そんな重くないので、普通にシェルで書きます。
ところで、UbuntuへのDockerインストールは、Ubuntuがメンテナンスしているdocker.ioというパッケージか、Docker自体がメンテナンスしている奴のどっちかで基本的に導入しみあす。今回は、docker.ioのバージョンがかなり古かったため、Dockerがメンテナンスしているパッケージにしときました。
# !/usr/bin/env bash
apt-get update -y
apt-get install -y language-pack-ja python-pip
apt-get install apt-transport-https
apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9
sh -c "echo deb https://get.docker.com/ubuntu docker main\
> /etc/apt/sources.list.d/docker.list"
apt-get update -y
apt-get install -y lxc-docker
pip install -U fig
fig用のymlも書いておきます。中身は前述のサイトそのまんまです。
hub:
image: selenium/hub
ports:
- "4444"
node:
image: selenium/node-firefox
expose:
- "5555"
links:
- hub
インスタンスの起動〜figでコンテナのセットアップ
$ vagrant up
$ vagrant ssh
$ cd /vagrant && sudo fig up -d hub
こんな感じで。最初はダウンロードとかがあるので、多分10分くらいは待ちます。
さて、起動が終わったら、接続の確認をします。参考サイトでは、Mac上でos2dockerを利用していて、こっちは生のVagrantですが、ぶっちゃけ確認方法は一緒です。
sudo docker port vagrant_hub_1
で表示されるポートに対して、http://:<上のポート>/grid/console でアクセスすると、Selenium Gridの画面が表示されるはずです。
問題なければここで fig scale node=5 で指定したとおり、ちゃんと5つのnodeが表示されているはず。
Turnip + Capybaraを利用する
さて、本題その2です。
これらは、実際にはEC2とかGCEとかのインスタンス内で実行する形なので、Vagrant内で実行させる形になります。
本当はプロビジョニングするときにrbenvとかも書けばよかったんですが、とりあえずは割愛ということで。
必要なGemのインストール
以下のようなGemfileを用意して、 bundle install
します。ちなみに今回は rspec 経由で実行させます。
source 'https://rubygems.org'
gem 'rspec'
gem 'turnip
gem 'capybara'
gem 'selenium-webdriver'
turnip_helper.rb
turnipが読み込むヘルパーを作っておきます。実際にはこのファイルは /vagrant/spec/に置きます。
# coding: utf-8
require 'turnip'
require 'turnip/capybara'
require 'turnip/rspec'
require 'capybara'
# 各種driverの設定
Capybara.register_driver :selenium do |app|
Capybara::Selenium::Driver.new(app, :browser => :firefox, :url => 'http://localhost:<hubのポート>/wd/hub')
end
Capybara.configure do |config|
config.default_driver = :selenium
config.javascript_driver = :selenium
config.ignore_hidden_elements = true
config.default_wait_time = 30
end
Dir.glob("spec/steps/**/*steps.rb") { |f| load f, true }
ここでのミソは、hubへのアクセスの書き方でしょうか。実際には、docker port した結果を環境変数か何かで渡しておいて、それを解析してやったほうが良さそうな気はしてます。
そしたらあとはfeatureとstepsを書いていくだけです。
# encoding: utf-8
# language: ja
@common
機能: sample
sample for Kabypara and Turnip on selenium on docker.
シナリオ: Googleを訪問できれば成功
もし googleを訪問
ならば 成功
# encoding: utf-8
steps_for :common do
step 'googleを訪問' do
url = "http://www.google.com"
visit url
end
step '成功' do
expect(page).to have_content("検索")
end
end
この辺りはTurnipのページを参考に書いていけばいいんじゃないかと思います。
あと忘れてはいけないのが、公式ページには書いてあるのですが、.rspecというファイルを作成して、中に一行
-r turnip/rspec
って書いておく必要があります。
実際に確認するときは、普通に
bundle exec rspec
で、確認できます。ちなみに性能ですが、上の例だと単純にGoogleにアクセスしてるだけですが、おおよそ5秒程度かかります。まぁ、Vagrant内で実行しているので、実際にネイティブなDocker内で起動させればそれなり・・・なのかもしれません。
最後に
Turnip と Tunrip の間違いで動かなくてあれー?ってなったのは私だけじゃないはず。
参考サイト
参考というかほとんど丸パクリして組み合わせただけというか。有用な記事を公開してくださってありがとうございます!
http://qiita.com/moriyaman/items/af2a0264adbaaa0d2029
https://github.com/jnicklas/turnip
https://github.com/willnet/capybara-readme-ja
http://gongo.hatenablog.com/entry/2014/12/02/002148