失敗は一時の恥

パッケージソフト開発をしているプログラマが気の赴くままに何かを投稿するブログ.

Hello Selenium!

Hello Selenium!

この記事について

Web ブラウザを操作するテスト自動化ツールである Selenium を,初めて触ってみて試した内容を紹介します.

プログラミング言語Ruby を使っています.

最終的に下の gif アニメのように「検索エンジンに特定をキーワードを与えてやると,期待したサイトがトップヒットする」といった簡単なテスト (?) が実行できるようになりました.

f:id:snobutaka:20180325164930g:plain
Selenium を使い DuckDuckGo で "Ruby" と検索する様子

今回行った実装は GitHub のリポジトリにも置いてあります.

Selenium とは

Selenium とは……

Selenium automates browsers. That's it! What you do with that power is entirely up to you. Primarily, it is for automating web applications for testing purposes, but is certainly not limited to just that. Boring web-based administration tasks can (and should!) be automated as well.

(https://www.seleniumhq.org より)

Selenium とはブラウザを自動化するもので,Web アプリのテスト自動化に使えるし,それだけでなくブラウザを使った単純作業の自動化もできる,といったところでしょうか.

RubySelenium を動かす

セットアップ

RubySelenium を動かすには,selenium-webdriver という gem を使用します.

gem install selenium-webdriver

動かす Web ブラウザは,事前にインストールされている必要があります.今回は Firefox で試しました.

また,動かすブラウザを操作するための Selenium のドライバをインストールし,パスを通しておく必要があります.

Firefox を動かすには geckodriver というライブラリが必要なので,https://github.com/mozilla/geckodriver/releases からダウンロードし,パスが通ったところに配置します.

macOS を使っているならば,homebrew でインストールできます.

brew install geckodriver

実際に動かす

Ruby のコードから Selenium の driver オブジェクトを取得します.

requrie 'selenium-webdriver' 
driver = Selenium::WebDriver.for(:firefox)
driver.manage.timeouts.implicit_wait = 5

ここでは,Web ページの応答のタイムアウトを 5 秒に設定しています. implicit_wait を設定しておくと,プログラムを書く側で明示的に待ちを実装しなくても,ライブラリが勝手に 5 秒まで待ってくれるようになります.

driver を作成できたので,ブラウザを操作してみます. Selenium でブラウザを操作するには,要素の ID や XPath で対象を選択し, それに対して入力やクリックのメソッドを呼び出す形になります.

次のコードでは,

  • 検索エンジンDuckDuckGo を開く
  • 検索ワードに "Ruby" と入力する
  • 検索実行ボタンをクリックする
  • 検索結果一覧から,トップヒットしているものをクリックする

という操作を行っています.

driver.get('https://duckduckgo.com')
driver.find_element(:id => 'search_form_input_homepage').send_keys('Ruby')
driver.find_element(:id => 'search_button_homepage').click()
driver.find_element(:id => 'r1-0').click()

ついでに開いている画面のスクリーンショットを撮ることもできます. テストのエビデンスが求められるシチュエーションで活躍しそうですね!

せっかくなのでエビデンスとしてスクショを撮って,driver を quit して終わらせましょう.

driver.save_screenshot('./duckduckgo-ruby.png')
driver.quit()

エビデンスを見ると,プログラミング言語 Ruby のサイトが最後に表示されていたことが確認できますね.

f:id:snobutaka:20180325165058p:plain
エビデンス

そういえば今回は,検索ワードに対して期待した結果がトップヒットするという「テスト」を書こうとしていたのでした. driver から現在のページの URL を取得すれば,検証が行えます.

assert_equal('www.ruby-lang.org', URI.parse(@driver.current_url).host)

ここまでの内容をまとめると,次のようなテストクラスにできます.

require 'selenium-webdriver'
require 'test/unit'
require 'uri'

class SeleniumFirefoxTest < Test::Unit::TestCase
  def setup()
    @driver = Selenium::WebDriver.for(:firefox)
    @driver.manage.timeouts.implicit_wait = 5 # seconds
  end

  def teardown()
    @driver.quit()
  end

  def test_duckduckgo()
    @driver.get('https://duckduckgo.com')
    @driver.find_element(:id => 'search_form_input_homepage').send_keys('Ruby')
    @driver.find_element(:id => 'search_button_homepage').click()
    @driver.find_element(:id => 'r1-0').click()
    @driver.save_screenshot('./duckduckgo-ruby.png')
    assert_equal('www.ruby-lang.org', URI.parse(@driver.current_url).host)
  end
end

GitHub のコード

ここまでの内容をもう少し拡張したものを GitHub のリポジトリ に置いてあります. リポジトリの中では,今回使用した DuckDuckGo 以外に

といったサイトでも検索を行うテストメソッドを用意しています.

ブラウザについては,今回の Firefox 以外に

で動かすテストクラスがあります. GUI がない環境でテストを実行する場合は,Headless モードで動かすことになります.

実行環境

上述のリポジトリにはテストコード以外に,Docker と Vagrant による実行環境がそれぞれ用意してあります. いずれの環境も Firefox が使えるようにしてあります.

画面にブラウザを表示して動く様子が見たい場合は Vagrant仮想マシン,Headless モードを動かして見たい場合は Docker イメージが使えます.

Docker イメージは Docker Hub にも公開してあります: snobutaka/hello-selenium

おわり

今回は初めての Selenium ということで非常に簡単なテストを書いてみました.

仕事で使ってみたり,ブラウザ作業自動化ライフハックに使ったりしてみたいものです.