18
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Selenium/AppiumAdvent Calendar 2017

Day 16

ChromeとHeadless Chromeの速さを比べてみた

Last updated at Posted at 2017-12-15

この記事はSelenium/Appium Advent Calendar 2017の16日目の記事です。

業務で自動システムテスト(E2Eテスト)の運用・開発を行っています。
数年ほど運用を続けていて、ブラウザはfirefox、IE、Chrome、OSもLinux、Windows、macOSと色々と試してきました。
どのブラウザ、どのOSでテストするかは必要となるテスト内容によって変わってきますよね。

本記事ではHeadless Chromiumの導入調査をした際の内容をまとめようと思います。
Headlessに求めるものはやはりスピードですよね。
導入調査ではHead有り・無しのブラウザ操作時の速度を計測してみました。

はじめに結論 :point_up:

計測結果からわかったこと

  • 計測したすべての操作でheadless chromeのほうが速い
  • 特にブラウザの起動は1/3近く短縮できる

調査してみて思ったこと

  • テストコードを実装するときはheadありのほうがデバッグしやすい
    • ただし、プロダクトの開発に合わせてテスト実行する時はheadless、テストコードのメンテや新規追加する時はheadありにしたりすると結果に違いが出るかもしれないので注意が必要
  • headlessでできないseleniumによる操作がありそうなのでその点は更に調査が必要

-- 以下調査の詳細 -------------------------------------

準備 :pick:

以下の3つを準備

  1. 最低限のCRUD機能を持つサンプルWebアプリケーション(テスト対象がWebアプリのため)
  2. Webアプリのデータを登録するDB
  3. Selenium実行環境(SeleniumServerとChromeを起動する環境)

構築・破棄、コードでの変更管理が楽なので、dockerコンテナで構築しました。(本題ではないので、手順は最後に記載します)
計測用のrubyスクリプトを実行し、サンプルウェブアプリケーションに対してseleniumでユーザ操作を再現します。

measure_headless_chrome (1).png

計測 :stopwatch:

速くなる点が以下だと推測。その点に着目して計測しました。

  1. ページの表示
  2. テキスト入力
  3. フォームの送信
  4. ブラウザ起動

計測用のスクリプト作成

1) selenium-webdriverライブラリをインストール

bundlerをインストール
gem install bundler
gemライブラリの準備&install
mkdir headless_benchmark
cd headless_benchmark
bundle init
cat << EOS >> Gemfile
gem 'selenium-webdriver'
EOS
bundle install --path ./bundle

2) 計測用のrbファイルを作成

headless_benchmark.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

計測結果 :bar_chart:

※ 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)

準備(詳細):construction_worker_tone2:

サンプルWebアプリケーションとSelenium実行環境の構築

以下のコマンドを実行して構築しました。
一部設定ファイルの編集作業がありますので、残念ながらコピペのみでは完結しないので、ご注意下さい。

サンプル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で接続できます(デフォルトパスワード)
start_rails_app_for_selenium.png

また、http://localhost:4445/ を開くとselenium serverのページが開けます。

参考 :bow:

18
19
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?