UI Testing a Sencha App
こんにちは、ゼノフィkotsutsumiです。
数ヶ月前に、ビジネスロジックをテストしたりJavaScriptシンタックスを確認したりするための、 ユニットテストの書き方についてのブログ をポストしました。 エンタープライズアプリケーションを開発する時にはこの概念を理解する必要があります:変更がプロダクションにプッシュされる前にバグを見つけなければ、壊滅的な事態が発生する可能性があります。
前のブログポストで触れなかった点は「UI Testing」(インテグレーション・テストとも呼ばれています)についてです。 前のブログに書かれたコメントを読んで、このテーマに取り組みたくなりました。 コミュニティのフィードバックを聞いた上で、UIテストをExt JSのデモアプリケーションに追加して、エンタープライズアプリケーションのテスティングの戦略について述べましょう。
UIテストの概要
前の記事に書いたように、UIテストはユニットテストとよく混同されますが、同じものではありません。
UIテストは、画面上のエレメントの振る舞い(または見た目)が 静的に(例:フラットレンダー)も動的に(例:ユーザーがアクションを実行する)にも 期待通りに作用していることを主観的に確認します。 ユニットテストは短いコードの部分を隔離して客観的にアプリケーションロジックを確認します。
キーとなる違いは、テストが本質的に主観的であるか客観的であるかという点です。
この考えを一段階進めると、UIテストを構成する部品(QAテストとコンポーネントテスト)に分割できます。
- QAテストはユーザーが実際にアプリケーションを利用しているように、そのアプリケーションへの実際の操作をシミュレートします。
- コンポーネントテストは、独立した(そして再利用可能な)部分を隔離して、その部分の表示や動作を確認します。
この記事では両方のタイプのUIテストを見ていきましょう。
UIテストの共通の問題
正しいツールの選択
アプリケーションのルックスと複雑な操作をテストするのは膨大な仕事なですから、多くの開発者がQAの問題を十分に解決できるようなテストを実装することにもがき苦しんでいる(時には諦めてしまう)ことは、驚くべきことではありません。
おそらく、開発者にとって最も大きなハードルはこのタスクに最も合ったツールを選ぶ事です。 あるツールはアプリケーションをナビゲートするためにXPathやCSSセレクターに頼っていて;他のものは自動テストができるようするには、複雑なサーバーコンフィギュレーションが必要となります。 結局フレキシブルなツールを選ぶ事はとても重要で;QAテストはビジネスの条件やアプリケーションが変わりながら度々書き直す必要がありますので、簡単にテストを作れ維持できるようにすることが重要です。
私の経験では、Senchaのアプリケーションを対象にしたQAテストを書くニーズに答えられるツールは3つだけ見つかりました:
各ツールにはそれぞれに利点と弱点があります;とは言え、私の個人的な意見では設定が一番簡単なのはSiestaで、SiestaのAPIはSenchaのフレームワークとシームレスに動作します。
免責:他のUIテスティングのツールもありますので、私は全てを使ってみたとは言っていません;またSiestaは必ずこのスペースで「ベスト」なツールとも言っていません。 ただ自分の経験に基づいた意見を述べています。
模擬データ
UIテストについて、もう一つの重要な(しかもよく見落とされる)問題は、テストは通常、実際のAPIを対象にして書いてはいけないということです。 ソースに関係なく、APIは根本的に不確実です。サーバーはダウンするし、ネットワークはレイテンシを感じるし、予想外のバグが発生します。
UIテストの目的は表示と動作の確認です、ある時点の特定のデータの存在をテストするわけではありません。 UIテストは可能であればAPIの模擬データを用意しなければなりませんが、これは簡単に解決できる問題ではありません。 いくつかの実装ではAJAXリクエストの代わりに静的データを使い、また他の実装ではネットワークコールを模擬APIにリダイレクトします。
いくつかのJavaScript模擬ライブラリがありますが、このブログのポストではそのテーマにはを余り深く入り込まないことにします。 ただそれはよく挫折の元となりますので、この課題についてもっと問題意識を向上させたいと思います。 私はサンプルアプリケーションのAPIコールをスタブする為に Sinon.js を選びました。
このように言っても、実際のAPIを使いたい状況があるかもしれませんが、通常はリリースが実際にプッシュできるかどうかを確認をする時だけにすることを推奨します。
サンプルアプリケーション
In the サンプルのExt JSアプリケーション の/ui-tests/フォルダーの中にはSiestaで書かれたQA(/app/)とコンポーネント(/ux/)があります。
QAテスト
/app/フォルダーの下にindex.htmlファイルがあります、ブラウザーで表示すると、そこにQAテストが配置されたSiestaインタフェースが表示されます。 ここの目的は実際のアプリケーションを起動して、ユーザーが望む実際の操作をテストすることです。 サンプルのアプリケーションは割と単純な例ですが、その二つのQAテストはアプリケーション全体の動作を多様な形でテストをできる事をデモンストレーションします。
「Test tabs for data in grids」(/app/tests/01_tabs.js) という題名の最初のテストは、単純にアプリケーションをロードして必要なビューが正確に配置されている事を確認します。 この例は初歩的ですが、もしアプリケーションでユーザー権限、設定、などのロジックに基づいたインターフェースを動的に作った場合は、このようなテストがとても便利となります。
二つ目のテスト、題名は「Test double-click functionality」(/app/tests/02_RsvpWindow.js)は再びアプリケーション全体をロードします。 今回は求めている動作が予想通りに実行することを確かめるために、始めにグリッドとタブを一緒に操作するシミュレーションをします。
私はこのデータストアのJsonPリクエストを記述部するためにSinon.jsを使っています。ここがポイントです。 こうすると実際のAPIがアクセス可能で正確に動作している事が前提でなくても、アプリケーションの機能性をテストできるようになります。 これを達成するにはいくつかの方法があります:私は模擬データを自動的に返すようにExt.data.JsonP.request()の動作をオーバーライドする事にしました。 (/ui-tests/app/api_stub.jsをご覧下さい).
コンポーネントテスト
/app/フォルダーの下にindex.htmlファイルがあります、ブラウザーで表示すると、そこにコンポーネントテストテストが配置されたSiestaインタフェースが表示されます。 QAテストと違って、この場合の目的は個別にコンポーネントの動作をテストすることです。 アプリケーション外でコンポーネントのテストをすると、既知のバグを隔離して将来の互換性を確保できます。
このサンプルアプリケーション`(/apuxp/tests/01_RsvpWindow.js)`に書いた唯一のテストはRsvpWindowビューの動作と表示を調べるものです。 デフォルトでこの(ウィンドウクラスを拡張した)ビューは、デフォルトのタイトルの300×300ピクセルのモーダルポップアップウィンドウです。 Siestaを使うとこのビューの単独のインスタンスを生成してデフォルトのコンフィギュレーションプロパティを確認します。
1 2 3 4 5 6 7 8 9 | var defaultWin = Ext.create('ChicagoMeetup.view.RsvpWindow', { //default configs }); t.is(defaultWin.modal, true, 'RsvpWindow should be modal.'); t.is(defaultWin.title, 'RSVPs for the selected Meetup', 'RsvpWindow should have a title of "RSVPs for the selected Meetup".'); t.is(defaultWin.getHeight(), 300, 'RsvpWindow should be 300px tall.'); t.is(defaultWin.getWidth(), 300, 'RsvpWindow should be 300px wide.'); t.is(defaultWin.getLayout().type, 'fit', 'RsvpWindow should have "fit" layout.'); |
これは確かに便利ですが、RsvpWindowが再利用可能なようにカスタマイズするのは良い考えです。 我々のSiestaのテストでもう一つのRsvpWindowのインスタンスを作れますが、今回は無事に初期できる事を確保する為にデフォルトの値をオーバーライドします。
1 2 3 4 5 6 7 8 9 10 11 12 13 | var customWin = Ext.create('ChicagoMeetup.view.RsvpWindow', { modal : false, title : 'Foobar Window', height : 400, width : 200, layout : 'card' }); t.is(customWin.modal, false, 'RsvpWindow should be modal.'); t.is(customWin.title, 'Foobar Window', 'RsvpWindow should have a title of "Foobar Window".'); t.is(customWin.getHeight(), 400, 'RsvpWindow should be 300px tall.'); t.is(customWin.getWidth(), 200, 'RsvpWindow should be 300px wide.'); t.is(customWin.getLayout().type, 'card', 'RsvpWindow should have "card" layout.'); |
Siestaの堅牢なテストAPIを利用して、このコンポーネントを使って多様な操作(クリック、ドラッグなど)をシミュレーションできます。 RsvpWindowのコンポーネントはあまりエキサイティングではありませんが、あなた自身のカスタムUXクラスでの可能性を想像できます。
結論
Webアプリケーションの為のユニットテストを作るのは難しいタスクかもしれませんが、それをしっかり行うと、その努力からの見返りはとても貴重です。 最後に重要なポイントを繰り返しましょう:
- ユニットテストとUIテストは同じものではない。 双方ともコードの安定性を保守する重要な方法ですが、二つはそれぞれ違う問題を解決します。
- シンタクスに気をつけて。 一つのブラウザーであなたのアプリケーションが問題なく動作する事で、全てのブラウザで正しく動作するわけではありません。
- カスタムコンポーネントをテストして。 あなたのフレームワークが予想通りに動作する事を想定するのはよいのですが、UXが正しく書かれている事を想定してはいけないのです。
- 100%のコードカバレッジを狙わないで。 アプリケーションを全部テストしたいと思うかもしれませんが、凝ったテストスイートを保つコストも考えて下さい。
ユニットテストについてのこのブログポストのシリーズは自分がSenchaのお客さまの問題を解決してきた経験に基づいています。 詳しく知りたければ、Ext JSと・又はTouchのアプリケーションをテストできる現実的な方法を開発者に紹介するWebinarをMats Bryntseと一緒に1月31日に主催します。 ここで登録できます。 その上、この下で自分の体験や考えを教えて下さい。 一緒にWebアプリケーションのテストをより実行しやすくできます。
訳注:Webinarは終了しましたが、 Vimeo で見ることができます。