この記事はSelenium/Appium Advent Calendar 2017の16日目の記事です。
業務で自動システムテスト(E2Eテスト)の運用・開発を行っています。
数年ほど運用を続けていて、ブラウザはfirefox、IE、Chrome、OSもLinux、Windows、macOSと色々と試してきました。
どのブラウザ、どのOSでテストするかは必要となるテスト内容によって変わってきますよね。
本記事ではHeadless Chromiumの導入調査をした際の内容をまとめようと思います。
Headlessに求めるものはやはりスピードですよね。
導入調査ではHead有り・無しのブラウザ操作時の速度を計測してみました。
はじめに結論
計測結果からわかったこと
- 計測したすべての操作でheadless chromeのほうが速い
- 特にブラウザの起動は1/3近く短縮できる
調査してみて思ったこと
- テストコードを実装するときはheadありのほうがデバッグしやすい
- ただし、プロダクトの開発に合わせてテスト実行する時はheadless、テストコードのメンテや新規追加する時はheadありにしたりすると結果に違いが出るかもしれないので注意が必要
- headlessでできないseleniumによる操作がありそうなのでその点は更に調査が必要
-- 以下調査の詳細 -------------------------------------
準備
以下の3つを準備
- 最低限のCRUD機能を持つサンプルWebアプリケーション(テスト対象がWebアプリのため)
- Webアプリのデータを登録するDB
- Selenium実行環境(SeleniumServerとChromeを起動する環境)
構築・破棄、コードでの変更管理が楽なので、dockerコンテナで構築しました。(本題ではないので、手順は最後に記載します)
計測用のrubyスクリプトを実行し、サンプルウェブアプリケーションに対してseleniumでユーザ操作を再現します。
計測
速くなる点が以下だと推測。その点に着目して計測しました。
- ページの表示
- テキスト入力
- フォームの送信
- ブラウザ起動
計測用のスクリプト作成
1) selenium-webdriverライブラリをインストール
gem install bundler
mkdir headless_benchmark
cd headless_benchmark
bundle init
cat << EOS >> Gemfile
gem 'selenium-webdriver'
EOS
bundle install --path ./bundle
2) 計測用のrbファイルを作成
#!/usr/bin/env ruby
require 'benchmark'
require 'selenium-webdriver'
SELENIUM_URL = 'http://localhost:4445/wd/hub'.freeze
def create_headless_driver
caps = Selenium::WebDriver::Remote::Capabilities.chrome("chromeOptions" => {args: ["--headless", "--disable-gpu", "window-size=1280x800"]})
Selenium::WebDriver.for :remote, url: SELENIUM_URL, desired_capabilities: caps
end
def create_driver
Selenium::WebDriver.for :remote, url: SELENIUM_URL, desired_capabilities: :chrome
end
APP_TOP = 'http://web:3000/users'.freeze
Benchmark.bmbm 10 do |r|
# ページの表示
r.report 'headless: load page:' do
driver = create_headless_driver
30.times do |num|
driver.navigate.to APP_TOP
end
driver.quit
end
r.report 'not headless: load page:' do
driver = create_driver
30.times do |num|
driver.navigate.to APP_TOP
end
driver.quit
end
# テキスト入力
r.report 'headless: input text:' do
driver = create_headless_driver
driver.navigate.to "#{APP_TOP}/new"
30.times do |num|
elem_name = driver.find_element(:css, '#user_name')
elem_name.send_keys 'name name'
elem_email = driver.find_element(:css, '#user_email')
elem_email.send_keys 'user@email.com'
elem_name.clear
elem_email.clear
end
driver.quit
end
r.report 'not headless: input text:' do
driver = create_driver
driver.navigate.to "#{APP_TOP}/new"
30.times do |num|
elem_name = driver.find_element(:css, '#user_name')
elem_name.send_keys "name name"
elem_email = driver.find_element(:css, '#user_email')
elem_email.send_keys 'user@email.com'
elem_name.clear
elem_email.clear
end
driver.quit
end
# フォームの送信
r.report 'headless: submit:' do
driver = create_headless_driver
30.times do |num|
driver.navigate.to "#{APP_TOP}/new"
elem_name = driver.find_element(:css, '#user_name')
elem_name.send_keys "name name #{num}"
elem_email = driver.find_element(:css, '#user_email')
elem_email.send_keys "user#{num}@email.com"
elem_email.submit
end
driver.quit
end
r.report 'not headless: submit:' do
driver = create_driver
30.times do |num|
driver.navigate.to "#{APP_TOP}/new"
elem_name = driver.find_element(:css, '#user_name')
elem_name.send_keys "name name #{num}"
elem_email = driver.find_element(:css, '#user_email')
elem_email.send_keys "user#{num}@email.com"
elem_email.submit
end
driver.quit
end
# ブラウザの起動
r.report 'headless: launch browser' do
30.times do |num|
driver = create_headless_driver
driver.quit
end
end
r.report 'not headless: launch browser' do
30.times do |num|
driver = create_driver
driver.quit
end
end
end
計測結果
※ real = 実経過時間です
bundle exec ruby headless_benchmark.rb
Rehearsal ----------------------------------------------------------------
省略
-------
user system total real
# ページの表示
headless: load page: 0.030000 0.010000 0.040000 ( 9.278591)
not headless: load page: 0.030000 0.010000 0.040000 ( 11.709836)
# テキスト入力
headless: input text: 0.130000 0.050000 0.180000 ( 8.656509)
not headless: input text: 0.140000 0.050000 0.190000 ( 11.224485)
# フォームの送信
headless: submit: 0.140000 0.050000 0.190000 ( 20.451673)
not headless: submit: 0.140000 0.050000 0.190000 ( 29.014519)
# ブラウザの起動
headless: launch browser 0.120000 0.030000 0.150000 ( 10.355756)
not headless: launch browser 0.090000 0.020000 0.110000 ( 28.746675)
準備(詳細)
サンプルWebアプリケーションとSelenium実行環境の構築
以下のコマンドを実行して構築しました。
一部設定ファイルの編集作業がありますので、残念ながらコピペのみでは完結しないので、ご注意下さい。
mkdir sample_app
cd sample_app
docker pull ruby
docker pull mysql
# railsコンテナ用のDockerfile作成
cat << EOS > Dockerfile
FROM ruby
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
RUN mkdir -p /sample_app
WORKDIR /sample_app
RUN gem install bundler
ADD Gemfile Gemfile
ADD Gemfile.lock Gemfile.lock
RUN bundle install
ADD . /sample_app
EOS
# Gemfile/Gemfile.lock作成
cat << EOS > Gemfile
source 'https://rubygems.org'
gem 'rails'
EOS
touch Gemfile.lock
# rails,mysql,selenium standaloneのコンテナ起動するdocker-composeファイル
cat << EOS > docker-compose.yml
version: '3'
services:
db:
image: mysql
environment:
- MYSQL_ROOT_PASSWORD=password
web:
build: .
command: bundle exec rails s -p 3000 -b '0.0.0.0'
volumes:
- .:/sample_app
ports:
- "3000:3000"
depends_on:
- db
sss-chrome-debug:
image: selenium/standalone-chrome-debug
ports:
- "4445:4444"
- "5901:5900"
depends_on:
- web
EOS
# railsアプリケーションファイルの作成
docker-compose run web rails new . --force --database=mysql --skip-bundle
# database設定の修正
vi config/database.yml
# ------
default: &default
adapter: mysql2
encoding: utf8
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
password: password # 修正箇所1
host: db # 修正箇所2
# ------
# ビルド
docker-compose build
# コンテナ起動
docker-compose up -d
# テーブルの作成
docker-compose run web rake db:create
# ユーザ登録テーブル、コントローラービュー作成
docker-compose run web rails generate scaffold User name:string email:string
# テーブル追加
docker-compose run web rake db:migrate
# コンテナ確認
docker ps
VNCビューワーからsampleapp_sss-chrome-debug_1コンテナに接続し、コンテナ内のchromeから http://web:3000/users (ローカルでみるときはhttp://localhost:3000/users) が開ければ準備完了。
sss-chrome-debugコンテナへはVNCビューワーからlocalhost:5901、パスワードはsecretで接続できます(デフォルトパスワード)
また、http://localhost:4445/ を開くとselenium serverのページが開けます。