クロスブラウザテストのクラウド実行環境 Sauce Labs について

この記事は、Selenium/Appium Advent Calendar 2014 の21日目の記事です。 前回は18日目、akasakas さんの SeleniumWebdriver で Jenkins から Firefox 多重起動時 の 「e is null」エラー対処法 でした。

はじめに

今回は Seleniumクロスブラウザテストをクラウド上で実行できるサービス、Sauce Labs ネタです。

  • Sauce Labs の紹介
  • 実際に Sauce Labs を使ってみた様子

について書いてみようと思います。

この記事では、以下の環境を利用しています。

  • Ruby 2.1.5
  • Gem パッケージ

Sauce Labs とは

Sauce Labs (https://saucelabs.com/) とは、OS/ブラウザ横断の自動テスト実行環境をクラウド上に提供しているサービスです。非常に豊富な OS/ブラウザ が利用可能となっており、それらを自前で準備・メンテするコストが不要になることが大きな特徴です。 Sauce Labs は Selenium の実行環境の他に

の実行環境も提供していますが、今回は割愛します。

利用できる OS/ブラウザ

この記事の執筆時点では、465もの OS/ブラウザ (+デバイス)を利用することができます。詳しくは 公式の Platform リスト にありますが、

といったバリエーションが用意されており、一般的なOS/ブラウザの組み合わせはほぼ網羅できています。

テストレポート

Sauce Labs 上で実行したテストは、その結果も確認できるようになっています。

といった情報が記録されています。これらのレポートを出力する処理を実装しないで済むので、非常に便利です。特にスクリーンキャスト(動画)は、テスト実行の様子がそのまま録画されているので、テストが落ちた際のシューティングに役立ちます。

また、複数アカウントのチームマネジメントにも対応しているため、アカウントによってテスト結果を見せる・見せないといった制御も可能になっています。

Firewall 内のサーバにもアクセスできる Sauce Connect

実際に Selenium のテストを実行したい対象のアプリは社内ネットワーク内からのみアクセスできる開発環境などに置いてあることが多いと思いますが、そういった環境にも Sauce Labs のサーバからアクセスできるようにするのが Sauce Connect です。

f:id:deme0607:20141221132703p:plain

Sauce Connect のイメージ図 (公式ドキュメントから引用)

テスト対象のサーバにアクセスできるマシンと Sauce Labs との間にトンネルを張ることで、外部ネットワークからのアクセスを遮断しているサーバに対しても Sauce Labs のテストを実行できるようになります。

Sauce Labs 上で Selenium のテストを動かす

ここでは実際に Sauce Labs を使って Selenium のブラウザテストを動かす様子を簡単にご紹介します。 Ruby + selenium-webdriver を使ってテストを実行するには、大きく分けて2つの方法があります。

  • Sauce Labs の Selenium Grid を直接利用する方法
    • 細かいカスタマイズが可能
    • 実装コストが多少大きい(特に並列実行周り)
  • Sauce Gem を利用する方法
    • Sauce Labs がリリースしている Sauce Gem を利用する
    • WebDriver, capybara や paralles-tests のラッパーとなっていて、既存のテストを簡単に Sauce Labs の並列テストに対応できる
    • WebDriver や Capybara をカスタマイズして利用しているような場合には導入が難しい

Sauce Labs の Selenium Grid を直接利用する方法

要は Sauce Labs とは Selenium Grid を提供しているサービスなので、 適切な Capability を指定して WebDriver の向き先を Souce Labs の Hub にしてやれば、既存のテストの実行環境を Sauce Labs に移すことができます。

Sauce Labs の Selenium Hub の URL http://ondemand.saucelabs.com:80/wd/hub に Sauce Labs のアカウント作成時に発行されるユーザ名と API KEY をつけて指定すれば OK です。

例えば、RSpec を利用しているようなケースでは

require 'selenium-webdriver'

RSpec.configure do |config|

    config.before(:each) do
        caps = Selenium::WebDriver::Remote::Capabilities.firefox
        caps.version = "34"
        caps.platform = "OS X 10.10"
        caps[:name] = self.example.metadata[:full_description]
        # caps[:name]: Sauce Labs 上で結果を確認する際のジョブ名

        @driver = Selenium::WebDriver.for(:remote,
            url: "http://SAUCE_USERNAME:SAUCE_API_KEY@ondemand.saucelabs.com:80/wd/hub",
            desired_capabilities: caps
        )
    end

    config.after(:each) do
        @driver.quit
    end

end

とすれば OS X 10.10 (Yosemite) 上で動作する Firefox34 の driver を取得することができます。

もちろん、Firefox の Profile も指定することができます。Capability を設定する際に Firefox の extension(firebug) の有効化と UA の指定をする処理はこのように書けます。

profile = ::Selenium::WebDriver::Firefox::Profile.new

profile.add_extension "../path/to/firebug.xpi"
profile["general.useragent.override"] = "Customized UserAgent" 

caps = Selenium::WebDriver::Remote::Capabilities.firefox(firefox_profile: profile)
caps.version = ...

また、Sauce Labs はジョブごとに指定した OS/ブラウザ の VM を起動するオーバヘッドがあるので、WebDriver を呼び出す際にタイムアウトを起こすことがあります。そういった場合には、一時的にタイムアウトを長めに設定しておくことでエラーを防ぐことができます。

http_client = ::Selenium::WebDriver::Remote::Http::Persistent.new
http_client.timeout = 300 # タイムアウトを長く設定

caps = Selenium::WebDriver::Remote::Capabilities.firefox
# Capability を設定

@driver = ::Selenium::WebDriver.for(:remote,
    url: "http://SAUCE_USERNAME:SAUCE_API_KEY@ondemand.saucelabs.com:80/wd/hub",
    desired_capabilities: caps,
    http_client: http_client,
)

http_client.timeout = 90 # 延長していたタイムアウトは元に戻しておく

Sauce Gem を利用する方法

公式のチュートリアルに記載されている方法はこちらの Sauce Gem を利用するパターンです。

この Gem パッケージぱ WebDriver, capybara や paralles-tests のラッパーとなっていて、既存のテストを比較的少ない変更で Sauce Labs のクロスブラウザ・並列実行テストに対応させることができます。

Gemfile に sauce を追加し、

rake sauce:install:spec

を実行すると Sauce Labs の設定を記述する sauce_helper.rb の生成と、spec_helper の修正が行われます。 あとは sauce_helper.rb で Capybara の driver と Sauce Labs の設定を記述すれば、:sauce = true タグのついたテストケースが Sauce Labs 上で実行されるようになります。

require "sauce"
require "sauce/capybara"
require "capybara/rspec"

Capybara.default_driver = :sauce

Sauce.config do |c|
  c[:browsers] = [
    ["Windows 8", "Internet Explorer", "10"],
    ["Windows 7", "Firefox", "20"],
    ["OS X 10.8", "Safari", "6"],
    ["Linux", "Chrome", nil]
  ]
end

sauce_helper の設定と、テストケースへの :sauce タグ付けが完了したら、Sauce Labs のユーザ名・アクセスキーを環境変数で渡して rake sauce:spec コマンドでテストが実行されます。

SAUCE_USERNAME=xxx SAUCE_ACCESS_KEY=xxx rake sauce:spec

sauce_helperc[:browsers] で指定した各 OS, ブラウザに対してのテストが paralles_tests を利用して並列に実行されます。 DB を利用するテストなど並列実行時にテスト間で副作用が発生してしまう場合は、paralles_tests と同じく ENV['TEST_ENV_NUMBER'] を使ってコンフリクトを避けるようにしておきます。

通常の paralles_tests はテストをファイルごとに分割して並列実行しますが、Sauce Gem ではパッチが当てられていてテストケースごとの分割で並列実行されます。テストの構造によっては、その点は注意が必要かもしれません。

まとめ

今回は最近実験的に触っている Sauce Labs について書いてみました。触ってみた感想としては、数多くのパターン・ノード数のブラウザテスト実行環境がメンテ不要・手軽に利用でき、その結果が記録されることはやはり素晴らしいです。

しかしテスト実行に毎回 VM の起動が伴う点、Sauce Labs のサーバが米国にある点から、ブラウザの起動やブラウザ <=> テスト対象サーバへのアクセスのオーバヘッドは手元のマシンや国内サーバでのテスト実行に比べると大きくなります。従って、テストの並列数が小さかったり、テストの実行時間そのものが長くないような場合には Sauce Labs のメリットは小さくなってしまいます。大量のOS/ブラウザでテストを実施したい場合・長時間かかるテストケースを並列実行してテスト実行時間を短縮したい場合などは、これだけの環境を自前の Selenium Grid で準備・メンテしていくコストを考えると非常に有効な選択肢になると思います。

Sauce Labs は 14日間 or 自動テスト80時間 の無料トライアルも用意されているので、興味のあるかたは是非こちらからサインアップして触ってみてください。 まだまだ実運用に向けたような情報は不足しているので、皆さまの Sauce Labs 情報発信を楽しみにしています!

Selenium/Appium Advent Calendar 2014、次の記事は machさん です。よろしくお願いします!