2013年12月4日水曜日

Selenium WebDriver でスクリーンショットを取得するときのtips

この記事は、Selenium Advent Calendar 2013の6日目の記事です。

ごあいさつ


はじめましてこんにちは。
株式会社Pro-SPIRE ソリューション事業部の戸田と申す者です。
現在は、主にSeleniumの環境構築や
Knockout.jsを使ったクライアントサイド開発を手がけています。

特に Selenium を中心とした自動テスト技術については
今後もどんどん重要になっていく分野だと確信していて、
チームメンバーも含めて、かなり入れ込んでいるところです。

検証事業としてもどんどん拡大していきたいと考えていますので、
お手元のシステムの検証でお困りだったり、
ご興味・ご関心がございましたら
ぜひ弊社にお声かけください!
精一杯サポートさせていただきます。

WebDriverでのスクリーンショット


さて、Selenium Advent Calendar 2013 向けの記事としまして、
些末ではございますが、弊社が Selenium を通して困った点や、解決方法について
よくあるお話を、ぜひ共有させていただこうと思います。
今回のテーマは「スクリーンショット」です。

Selenium でテストを実行するとき、いちばん大事なのはテストケースの成功・失敗ですが、
エビデンスとしてのスクリーンショットの取得も、非常に重要視されやすいところです。
同時に、なんでもない処理のように思われてけっこうはまりどころになりやすい部分でもあります。

WebDriver には、スクリーンショットを取得するAPIは1つしかありません。
Java の場合は、インターフェース TakesScreenshot の、 getScreenshotAs(OutputType<X> target) です。
http://selenium.googlecode.com/git/docs/api/java/org/openqa/selenium/TakesScreenshot.html#getScreenshotAs(org.openqa.selenium.OutputType)
ところが、このたったひとつのAPIは、Webブラウザーの種類によってずいぶん動作が異なっており、
複数ブラウザーで同じようにスクリーンショットを取得するためには、ちょっとずつ処理を変える必要があります。

シンプルな構成のWebページの場合


まず、Selenium Advent Calendar 2013 のページのような
シンプルな構成のWebページのスクリーンショットを取得してみましょう。


では いきます。はい。


ファッ!?

Chromeだけ、ページ全体の画像が取得できません…

これは、 ChromeDriver 2 の不具合として既に報告されている事象なのですが、
修正対応は難しい状況のようで、長い間この状態が続いています。
https://code.google.com/p/chromedriver/issues/detail?id=294
どうも ChromeDriver 1 であればページ全体の画像が取得できたらしいのですが、
ChromeDriver 2 では表示されている領域しか画像を取得できません。

ううむ、いきなりつまづいてしまいました…
ChromeDriver 1 を使うという方法もあります。が、ChromeDriver 1 は最新の Chrome に対応していません。
スクリーンショットのためだけに、なかなか安易には使えないのです…

この事象に対して、弊社では JavascriptExecutor を併用することで対応しています。
http://selenium.googlecode.com/git/docs/api/java/org/openqa/selenium/JavascriptExecutor.html
スクリーンショットを取得 --> JavaScript でスクロール --> スクリーンショットを取得 --> JavaScript でスクロール ... ...
と繰り返して、後で1枚の画像に合成する、という手順です。
Webブラウザーの種類によってはあからさまに動作速度が落ちるのが難点です。

フレーム構造を持つWebページの場合


上記の例は、あくまでもシンプルな構成のWebページでのお話でした。
実際にいろんな構成のWebページでスクリーンショットを取得すると、
また別の問題が出てきたりします。

たとえば、 <iframe> 要素を含む、インラインフレームのあるページではどうなるでしょうか。
次のような構成のページで、インラインフレームの中の「Learn more」ボタンをクリックした直後に
スクリーンショットを取得する、というシナリオの処理を実行させてみます。


ではいきます。はい。


ファッ!?

てんでバラバラですね。まったくわけがわからないよ(゚ω゚)

特にわけがわからないのは、 Internet Explorer で取得したスクリーンショットだと思います。
他のスクリーンショットとは、明らかに大きさが異なっています。

弊社内でいろいろ実験しましたところ、どうも Internet Explorer の場合だけ、
ボタンをクリックさせるために WebDriver.switchTo().frame() などで特定のフレームにフォーカスさせた状態にすると
そのフレームのサイズに合わせてスクリーンショットを取得しようとしてしまうようです。
役に立つときもたまにある動作ですが、まあだいたい困るときの方が多いです。

この事象に対して、弊社では Internet Explorer のときだけ
スクリーンショットを取得する前に、一時的に WebDriver.switchTo().defaultContent() などを実行して
最上位のフレームにフォーカスさせるようにしています。
スクリーンショットを取得した後は、フレームの中のテストを継続できるように、
元のフレームにフォーカスを戻します。

さらっと説明しましたが、この「元のフレームにフォーカスを戻す」というAPIも、
WebDriver には直接的なものが用意されていません。
元のフレームにちゃんとした ID や name 属性が設定されていればかんたんなのですが、
過去の資産を継承しているWebシステムなどでは
これらの属性が適切に設定されておらず、通常のロケーターでは対応できないことがあったりします。

そのような場合でも、弊社ではあきらめず JavascriptExecutor を併用してどうにか工夫しています。

同じAPIでもWebブラウザーにより動作に差異があることにあらかじめ注意しましょう


弊社ではこのようなWebブラウザー間の差異は
スクリーンショット取得用のクラスに細かい処理を隠蔽して吸収しているため、
テストコードの中で直接 getScreenshotAs() を記述することは無くなっています。
これから導入をお考えの方で、スクリーンショットの活用 特にクロスブラウザーチェックをお考えの方は、
このあたりの動作の差異について心の準備をしておくことをおすすめいたします。


長文となりましたが、ここまでお読みいただきありがとうございました。
Selenium の導入でお悩みなどがございましたら、ぜひ弊社までご一報ください!
弊社 お問い合わせページはこちら

0 件のコメント:

コメントを投稿