Developer's Blog

Selenium WebDriver を使った JavaScript 関連のテスト

こんにちはこんにちは! エンジニア川端です。

春ですね。花見ですね。フェンリルでも、大阪城公園に花見に行ってきました。
花は桜木、男は岩鬼。美しい桜を見てリフレッシュです。
Sleipnir 3 for Windows」を始めとする各プロダクトの開発者の面白い一面なども見る事ができ、楽しゅうございました。

花見に行くためには定時ダッシュしたいわけですが、そんな時に限ってバグを発見したり、テスト用のチェックシートが積み上がっていたりするものです。
繰り返し繰り返し行うテスト(レグレッション・テスト)は、できるだけ人手をかけずに行い、とっとと花見に 効率的な開発を行いたいもの。開発者のみなさんは色々工夫をされていることと思います。

私はラクダスキーなので、大体のものは Test::More とかでやってしまいますが、最近はちょっと「Selenium」も触ったりしてます。

「Selenium」といえば、使っていない人でも知っているくらい名前が売れているツールですね。Firefox のプラグイン「Selenium IDE」が有名ですが、今回とりあげるのは「Selenium WebDriver」です。色々な WEB ブラウザを使ったテストを、得意な開発言語で準備することができます。

ドキュメントを見ると、Java でやるのが一番色々できそうですが、ラクダスキーとしては、ここは Perl で。

Perl から利用するには、

  1. Selenium::Remote::Driverをインストールする
  2. selenium-server-standaloneをダウンロードして、起動しておく
    java -jar selenium-server-standalone-2.20.0.jar
  3. 使う
     use Selenium::Remote::Driver; my $d = Selenium::Remote::Driver->new(); $d->get('http://images.google.co.jp/images?q=%E8%8A%B1%E8%A6%8B'); print $d->get_title(); $d->quit(); 

    実行結果

    花見 - Google 検索

という感じです。他のスクリプト言語でも大体同じような感じですが、Ruby や Python だと standalone サーバの準備は不要です。それぞれ gem や pip でインストールしてください。

# gem install selenium-webdriver
# pip install selenium

JavaScript 関連の WEB テスト

HTML のページ遷移確認だけなら、どんなツールを使っても目的は達成できると思います。 Perl なら Test::WWW::Mechanize 等を使うとラクチンですね。
ただ、JavaScript が関連してくれとちょっと事情が違う。例えば、最初は表示されてないけど、クリックするとログインフォームが表示されるような画面。ページがロードされた時点ではログインフォーム自体が存在しなかったりするので、JavaScript を解釈できないテスト用ツールだとお手上げです。

そんな時には Selenium 。

サンプルとして、「Sleipnir Start」のテストをしてみましょう。
Sleipnir Start は、検索ワードを入力した後、いろんなサイトで検索が可能です。

Sleipnir Start にアクセス→キーワード「fenrir」と入力して、YouTube アイコンをクリック→YouTube での検索結果が別タブで開く

という挙動をテストしてみます。

 use Selenium::Remote::Driver; use Test::More tests => 1; my $d = Selenium::Remote::Driver->new(); # Sleipnir Start の YouTube アイコンをクリックした時の挙動を確認 # 期待される動作: 入力されたキーワードで YouTube 検索し、結果を別タブで表示 my $search_word = 'fenrir'; # Sleipnir Start トップページにアクセス $d->get("http://www.sleipnirstart.com"); # テキスト「fenrir」を入力 $d->find_element('//input[@id="search_txt"]')->send_keys($search_word); # YouTube アイコンをクリック $d->find_element('//input[@id="i_t"]')->click(); # ページが表示されるまで待つ wait_for_page_to_load($d,10000); # 検索結果のタブを選択 my $h = $d->get_window_handles(); $d->switch_to_window($h->[1]); # ページタイトルが「fenrir - YouTube」になっているかどうかチェック is $d->get_title(), $search_word.' - YouTube', 'search results title'; $d->quit(); # via https://github.com/aivaturi/Selenium-Remote-Driver/wiki/Example-Snippets sub wait_for_page_to_load { my ($driver,$timeout) = @_; my $ret = 0; my $sleeptime = 2000; # milliseconds $timeout = (defined $timeout) ? $timeout : 30000 ; do { sleep ($sleeptime/1000); # Sleep for the given sleeptime $timeout = $timeout - $sleeptime; } while (($driver->execute_script("return document.readyState") ne 'complete') && ($timeout > 0)); if ($driver->execute_script("return document.readyState") eq 'complete') { $ret = 1; } return $ret; } 

スクリプトを実行すると、ブラウザが起動し、文字の入力やクリックが自動で処理され、結果が返ってきました

ok 1 - search results title

入力したキーワードで YouTube で検索していることが確認できました。ラクチンですね!

スクロールキャプチャを撮る

自動実行結果を見るとエラーになってるんだけど、その時の画面はどんな感じになっているんだろう?……とエラーが出た URL をブラウザに入力して……
面倒ですね。

自動テストのエラー時にはスクリーンショットを撮るようにしておいて、画面を後で参照できれば随分楽かも。

そんな時には Selenium 。

先ほどの検索結果画面をキャプチャしてみます。

 use Selenium::Remote::Driver; use MIME::Base64; my $d = Selenium::Remote::Driver->new(); my $url='http://www.youtube.com/results?search_query=fenrir'; my $filename = '_screen_' . time() . '.png'; # YouTube の検索結果画面にアクセス $d->get($url); wait_for_page_to_load($d,10000); # スクリーンショット撮影 my $png = $d->screenshot(); # ファイルに保存 open my $fh, '>', $filename or die $!; binmode $fh; my $png = $d->screenshot(); print $fh MIME::Base64::decode_base64($png); close $fh; $d->quit(); # via https://github.com/aivaturi/Selenium-Remote-Driver/wiki/Example-Snippets sub wait_for_page_to_load { my ($driver,$timeout) = @_; my $ret = 0; my $sleeptime = 2000; # milliseconds $timeout = (defined $timeout) ? $timeout : 30000 ; do { sleep ($sleeptime/1000); # Sleep for the given sleeptime $timeout = $timeout - $sleeptime; } while (($driver->execute_script("return document.readyState") ne 'complete') && ($timeout > 0)); if ($driver->execute_script("return document.readyState") eq 'complete') { $ret = 1; } return $ret; } 

スクリプトを実行すると、ブラウザが起動して、指定 URL のスクリーンショットを撮影します。
縦に長い WEB ページもズルズルっとスクロールして、ページ全体をキャプチャしてくれるスクロールキャプチャ。色々使えそうです。

自動運転する

前述の例のように特に指定しない場合、Firefox が起動して処理を実行しますが、他の WEB ブラウザの指定も可能です。そこで注目したいのが「HTMLUnit」。

HtmlUnit is a “GUI-Less browser for Java programs”. It models HTML documents and provides an API that allows you to invoke pages, fill out forms, click links, etc… just like you do in your “normal” browser.

It has fairly good JavaScript support (which is constantly improving) and is able to work even with quite complex AJAX libraries, simulating either Firefox or Internet Explorer depending on the configuration you want to use.

ということで、GUI はないけど JavaScript は解釈してくれます。なんか「定期的に自動実行してスクレイピング」とかに大活躍しそうな香りが漂ってますね。

ブラウザ指定は、インスタンス生成時に行います。

 my $d = Selenium::Remote::Driver->new(browser_name => 'htmlunit'); 

気軽に効果的にテストしよう

あらゆるブラウザの動作チェックと気張らずに、基本的なテストを一通り実行する、という用途で使うだけでも幸せになれそうな「Selenium WebDriver」。

「みんな花見にいってしまったけど、僕はテストが終わってないので……」

というボッチを生み出さないために、Selenium の導入、いかがでしょうか?

Copyright © 2019 Fenrir Inc. All rights reserved.