品質保証へ最新の改良:スクリーンショットテスト
Piwik の 品質保証概要
いくつかの良いソフトウェア同様に、 Piwik には、単体テストと統合テストを含む包括的な品質保証スイートが付属しています。単体テストで Piwik のコアコンポーネントが適切に機能することを確認します。統合テストではトラッキングとレポート集計、 API が正しく機能していることを確認します。
私たちの品質保証スイートを完全なものにする為、新しいタイプのテストとして、 Piwik のコントローラ、および JavaScript コードが正しく動作することを確認する為のスクリーンショットテストを最近追加しました。
このブログ記事はそれらの動作やセットアップ、設定方法を私たちの経験に基づいて記述します;アクティブなオープンソースプロジェクトにおける革新的な品質保証の実践をお見せしたいと思います。
スクリーンショットテスト
名前の通り、私たちのスクリーンショットテストは、まず(1)URL のスクリーンショットをキャプチャし、次に(2)結果を予想されるイメージと比較します。これによって、単に URL を指定すれば Piwik のコントローラや、 JavaScript コードのテストができます。ページ内容の変更をテストする従来の UI テストとは異なります。殆どの場合、このようなテストでは HTML の変更を確認するために大量のテストコードを書込む必要があります。一方で私たちのテストは、最低限のテスト用コードで、CSS や JavaScript のレンダリングロジックにおける回帰を示すことができるようになります。
スクリーンショットをキャプチャ
スクリーンショットは、サードパーティのツールを使用してキャプチャされます。私たちは、 PhantomJS に決める前に、いくつかのツールを試してみました。 PhantomJS は、 WebKit 搭載のウェブビューを作成することができる環境で JavaScript ファイルを実行します。スクリーンショットをキャプチャする時に、以下のスクリプトを PhantomJS に渡します:
- ウェブページビューを開きます
- URL をロードします
- すべての AJAX 要求が、完了するまで待ちます
- すべての画像が読み込まれるまで待ちます
- すべての JavaScript が実行されるまで待ちます
その後、完成したページは、PNGファイルにレンダリングされます。
- PhantomJS の使い方を確認するには capture.js を参照してください。
- AJAX の要求を完了する方法、画像を待つ方法は override.js を参照してください。
スクリーンショットの比較
スクリーンショットが生成されると私たちは予想されるイメージと比較して UI 回帰テストをします。
曖昧なマッチングはありません。私たちは、イメージが同じバイト数で構成されているかを確認します。
スクリーンショットのテストが失敗した場合、私たちは画像の差分を生成するために ImageMagick’s の比較コマンドラインツールを使用します:
上記の例では、データテーブル内に、検索ボックスを非表示にしていた変更が見つかりました。
これは、データテーブル全体が数ピクセル分シフトアップしているとレポートされています。開発者に迅速なフィードバックが行えるように最後のコミットで違いを、赤色の表示に変更しました。
Travis のスクリーンショットテスト
私たちは異なったマシンで同一のスクリーンショットを生成する困難を経験し、従って私たちのテストは Travis によって当初自動化できませんでした。このハードルを超えた私たちは、 UI テストおよび、スクリーンショットを保存するために新しい github のレポジトリを作成した後、 Travis をビルドすることができました。また、 Piwik repo にコミットがプッシュされるたびに、私たちの Travis ビルドは、 UI テストを実行し、 UI テストレポへコミットすることを確認しました。
私たちは、メインリポジトリが大きな スクリーンショットファイル ( git がうまく処理できない)。によって負担がかからないように、新しいリポジトリを作成することを決めました。 さらに、 Travis ビルドが、サーバに生成されたスクリーンショットをすべてアップロードし、デバッグの障害がより容易になることを確実にしました。
私たちが経験した問題
別のマシンで同じようにレンダリングするために生成されたスクリーンショットを得ることはかなりの挑戦でした。
正しく取得する方法を見つけ出すために数ヶ月かかりました。それがここで、私たちが学んだことです:
フォントは別のマシンで同じようにレンダリングされますが、別のマシンでは、間違ったフォントを選択することがあります。 私たちが最初に Travis でこれらのテストを実行しようとした時、異なるマシン上でのフォントのレンダリング方法の小さな違いに気づきました。私たちは、これらのマシンにインストールされたライブラリのために発生する克服できない問題だと思いましたが、そのマシンが間違ったフォントを選択していたことが判明しました。私たちの Travis ビルド用に正しいフォントをインストールした後は、全てが動作し始めました。
GDの異なるバージョンは少し違った画像を生成する。 GD は Piwik でスパークライン画像を生成するのに使われています。異なったバージョンの GD はほんの少し異なった画像を生成します。肉眼で見ても同じに見えますが、いくつかのピクセルは少し異なるカラーになっています。これは、残念なことに、私たちには解決できない問題です。私たちはテストを実行する全てのユーザが同じバージョンの GD を使うことを確かめることはできません。従って UI テストにはスパークラインを使用しないことにしました。
What we learned about existing screenshot capturing tools
We tried several screenshot capturing tools before finding one that would work adequately. Here’s what we learned about them:
- CutyCapt This is the first screenshot capturing tool we tried. CutyCapt is a C++ program that uses QtWebKit to load and take a screenshot of a page. It can’t be used to capture multiple screenshots in one run and it can’t be used to wait for all AJAX/Images/JavaScript to complete/load (at least not currently).
- PhantomJS This is the solution we eventually chose. PhantomJS is a headless scriptable browser that currently uses WebKit as its rendering engine.For the most part, PhantomJS is the best solution we found. It reliably renders screenshots, allows JavaScript to be injected into pages it loads, and since it essentially just runs JavaScript code that you provide, it can be made to do whatever you want.
- SlimerJS SlimerJS is a clone of PhantomJS that uses Gecko as the rendering engine. It is meant to function similarly to PhantomJS. Unfortunately, due to some limitations hard-coded in Mozilla’s software, we couldn’t use it.For one, SlimerJS is not headless. There is, apparently, no way to do that when embedding Mozilla. You can, however, run it through xvfb, however the fact that it has to create a window means some odd things can happen. When using SlimerJS, we would sometimes end up with images where tooltips would display as if the mouse was hovering over an element. This inconsistency meant we couldn’t use it for our tests.
One tool we didn’t try was Selenium Webdriver. Although Selenium is traditionally used to create tests that check for HTML content, it can be used to generate screenshots. (Note: PhantomJS supports using a remote WebDriver.)
スクリーンショットテストの将来プラン
今のところ私たちは、たくさんのスクリーンショットを生成しています。 PHP のコードや JavaScript のコードや CSS がどのように Piwik のUI を表示しているかをテストしますが、どのように動くかはテストしていません。これは私たちの次のステップです。
私たちは Piwik の各 UI コントロールに対するスクリーンショット単体テスト(例えばデータテーブルビューあるいはサイトセレクタ)を作りたいと思っています。これらのテストは単体でコントロールをロードするためにウィジェット化されたプラグインを使います。そしてイベントやユーザの行動をシミュレートする JavaScript を実行し、最後にスクリーンショットを撮ります。こうして私たちはクリックやホバー等、全ての動作をテストできるようになります。
スクリーンショットテストは Piwik をより安定させ、敏速さを保ち、より速く、頻繁にリリースできるようにします。
Piwik を広め、サポートしていただき ありがとうございます!