リポジトリ:精神的オーバーヘッドの削減とテストメンテナンスの改善
DevOpsに移行する開発チームのためのシンプルな Web アプリケーションを考えてみましょう。開発チームのメンバーは、最低でも毎日、新しいコードを本番環境にデプロイしたいと考えています。しかし、それを実現するための十分な時間がありません。
開発メンバーは、テストツールを使用してアプリケーションを「稼働」させ、アプリケーションのメイン機能が適切に維持されるようにしたいと考えています。
たとえば、ログイン処理をテストするには、ツールに次のような操作をおこなわせる必要があります。
- ユーザー名のテキスト フィールドを見つけて入力する。
- パスワードのテキスト フィールドを見つけて入力する。
- 送信ボタンを見つけてクリックする。
- 次の画面に表示されるオブジェクトが、そこにあるか (またはないか) を確認する。
しかし、あるとき突然、ユーザーインターフェイスが変更され、すべてのテストが失敗したとします。その変更が小さなものであったとしても、依存するすべてのテストを修正しなければなりません。これには多くの修正作業が伴います。
オブジェクトへの最新の内部フックは、多くの場合、CSSまたはXPathの文字列です。 たとえば、「Submit」というラベルの付いたボタンへのXPathは次のようになります。
//button[@value=”Submit”]
CSSの場合は次のとおりです。
input[type=”button”,value=”Submit”]
テストでこれらの「固定の文字列」を使用するということは、文字列に変更があった場合、テスターはテストの修正のために、グローバルな検索と置換をおこなう必要があるということです。また、ログインページの特定のボタンだけが変更され、その他の送信ボタンは変更されない場合、検索と置換は手動での作業になります。
修正をおこなった後、テスターはテストを再実行し、修正した内容が正しいかどうかを確認する必要があります。テスト数が5個、あるいは500個でも、この確認には問題はないでしょう。
しかしながら、テスト数が5,000個に達すると、これは本質的にメンテナンス不可能な状態です。
修正方法:オブジェクトリポジトリ
Ranorexにおけるオブジェクトリポジトリとは、オブジェクトのプロパティ (exists, enabled, visible, innerText, tagName, classなど) とツリー トラバーサル パス ロケーター(Tree traversal path locators)の集合体であり、Webページの基礎となるコードのようにツリー構造になっています。
また、オブジェクトのスクリーンキャプチャや比較によるビジュアルテストは、オブジェクトリポジトリの機能を拡張します。テストが失敗した場合に、「テストが実際に成功したことを確認し、将来の比較のために新しいイメージを使用する」という単純な作業でテストの修正が済み、テストを更新するためのコストが大幅に削減され、メンテナンスが容易になります。
ツリーはユーザーインターフェイスの構造(Web、ドキュメント オブジェクト モデル、または DOM の場合)に基づいてモデル化されているため、オブジェクトブラウザーは、ページタイトルやリンクされたJavaScriptファイルなど、直接クリックできないDOMの部分にアクセスすることができます。
したがって、コントロールが別の場所に移動した場合、オブジェクトをクリックしてオブジェクト リポジトリを開き、「Track」 をクリックして新しい場所を記録するか、コントロールがあった XPathまたは CSSのロケーターを手動により直ぐに調整することができます。次のようなロケーターを想像してください。
/dom[@domain='www.mydomain.com']//div[#'top-posts-2']/h4[@innertext='Top Posts & Pages']
このロケーターについて、上位の投稿ページ (Top Posts & Pages) から、最近の投稿ページ (Recent Posts & Pages) を参照するよう、場所と内部テキストの両方が変更されたとします。これは次のようになります。
/dom[@domain='www.mydomain.com’]//div[#'recent-posts-2']/h4[@innertext='Recent Posts & Pages']
新しいオブジェクトを指定する変更を加えるために、すべてのテストスクリプトを開いて修正を加える必要はなく、オブジェクトリポジトリでインラインで変更できます。
優れたオブジェクトリポジトリにはプロパティビューがあり、簡単な操作でプロパティの値を変更してロケーターを改善できます。この例では、ロケーターのパスを構成するさまざまなノードが、必要なWeb要素のパス上の任意のポイントで更新されていることに注目してください。
このオブジェクトリポジトリでは、必要に応じて、レコーディング、テキストのインラインでの更新、パスに含まれるプロパティの変更、といった操作によってパスに変更を加え、「適用」をクリックして保存できます。この 1 つの要素に小さな修正を加えるだけで、自分でコードを確認する時間がどれだけ削減されるか想像してみてください。
オブジェクトリポジトリは、テスト自動化担当者が重要なことに集中できるようにするために大いに役立ちます。これは、テストの自動化を作成するときに発生する可能性のある初期の問題のほとんどを解決します。
しかしそれでも、テスト自動化担当者は問題に遭遇する可能性があります。
テスト自動化担当者の課題
一部のコンポーネントには、強力で認識可能な名前が付いていない場合があります。たとえば、あるラジオボタンは、ある radiogroupの10個のラジオボタンのうちの 1 つであり、すべてが “radiobutton1” や “radiobutton2” などと呼ばれているかもしれません。また、それはページ上で、あるいはテスト対象アプリケーション全体でも、唯一のラジオボタン グループではないかもしれません。オブジェクト リポジトリを使用することで、テストで使用される名前を、”smbRadioBtn” や “entRadioBtn” など、より意味のある名前に変更できます。プログラマーが名前を提供しない場合でも、オブジェクト リポジトリはオブジェクトを見つけることができ、テスターはそのオブジェクトに名前を付けることができます。
オブジェクトを照合するために何を使用するかという前提には、頻繁に変更されるプロパティが含まれる場合があります。このような場合、対象のオブジェクトがまだ画面に表示されていても、その認識に失敗してしまう可能性があります。これに対するペストプラクティスは、変更の可能性が低く、ページ上でユニークであり続ける可能性が高いプロパティを、オブジェクトと紐づけることです。
より優れたロケーターは、特定のテキストを持つ “button“を見つけることができるようになるので、位置の情報が重要でない限り、ページ上のボタンの位置に縛られません。一部のツールは、アプリケーションと共に、これらの変化を時間の経過とともに観察し、機械学習を使用してオブジェクトがいつ移動したかを「推測」できます。このようなツールは市場に登場し始めたばかりであり、私達は自己修復(セルフヒーリング)ツールと呼んでいます。
オブジェクトリポジトリは、あまり良い名前ではないオブジェクトのロケーターの問題を解決しますが、他の問題を引き起こす可能性があります。たとえば、複数の開発チームが同じ Web サイトで作業している場合、2つの開発チームが同じページに変更を加え、他の開発チームが作業しているテストで失敗がレポートされる可能性があります。このような問題は、オブジェクトリポジトリの有無にかかわらず発生しますが、オブジェクトリポジトリをコードと一緒にバージョン管理したり、ブランチに配置する必要があるかもしれません。
調整のためのレイヤーが余分にあることは、複雑さを増す原因となります。しかし、オブジェクトに名前を付けて再利用することで、プロセスは単純になります。 オブジェクトリポジトリは、オブジェクトへの接続方法を保持するコードライブラリのようなものだと考えてください。
テストの保守が難しくなっている場合は、オブジェクトリポジトリを含むツールを検討することをお勧めします。 私の経験では、ツールを追加しないと、いずれにせよ自分でツールを作成することになりますが、注意しない限り、扱いにくく、壊れやすく、必要な機能の半分しか備えていないものになる可能性があります。時間と労力を節約し、オブジェクトリポジトリについて既存の選択肢を検討しましょう。そうすれば、頭を悩ますいくつかの頭痛の種を取り除くことができるでしょう。
作者について:
Timothy Westernは、政府機関、クラウド コンピューティング、マーケティング オートメーションの分野で15年以上の経験を持つソフトウェア エンジニアであり、開発者でありテスターです。米国国防総省、米国郵政公社、Rackspace などでのサポート経験があります。また、Delivery 24/7 Software Community の創設メンバーでもあります。
(この記事は、開発元 Ranorex 社 Blog 「Repositories: Reduce Mental Overhead and Improve Test Maintenance」2019年5月16日の翻訳記事です。)