web-dev-qa-db-ja.com

ページオブジェクトモデル:ページメソッドにアサーションを含めないのはなぜですか?

初めてのポスター。私は長年UIオートメーションに取り組んできましたが、ページオブジェクトモデルを使用するように紹介された/指示されたのはごく最近のことです。そのほとんどは常識であり、私がすでに使用しているテクニックが含まれていますが、十分な理由のある説明を広範囲に検索したにもかかわらず、私が自分の心で正当化することができなかった特定の細かい点があります。 POMを自分のベストプラクティスと統合しようとすると、この質問がいくつかの驚きを引き起こしたので、ここの誰かが私を啓発してくれることを願っています。

から http://code.google.com/p/Selenium/wiki/PageObjects

上記のコードは重要なポイントを示しています。Pag​​eObjectsではなくテストがページの状態に関するアサーションを作成する必要があります。もちろん、すべてのガイドラインと同様に、例外があります。

から http://seleniumhq.org/docs/06_test_design_considerations.html#chapter06-reference

ページオブジェクトの設計方法には多くの柔軟性がありますが、テストコードの望ましい保守性を実現するための基本的なルールがいくつかあります。ページオブジェクト自体が検証やアサーションを行うことはできません。これはテストの一部であり、ページオブジェクトではなく、常にテストのコード内に含める必要があります。ページオブジェクトには、ページの表現と、ページがメソッドを介して提供するサービスが含まれますが、テスト対象に関連するコードはページオブジェクト内に存在しないようにする必要があります。

ページオブジェクト内に存在できる、または存在する必要がある単一の検証が1つあります。これは、ページ、および場合によってはページ上の重要な要素が正しくロードされたことを検証することです。この検証は、ページオブジェクトをインスタンス化するときに実行する必要があります。

これらの「ガイドライン」は両方とも潜在的な例外を考慮に入れていますが、私は基本的な前提にこれ以上同意することはできませんでした。私は「ページメソッド」内でかなりの量の検証を行うことに慣れています。検証の存在は、さまざまなコンテキストで問題を見つけるための強力な手法があると思います(つまり、検証はメソッドが呼び出されるたびに発生します)。特定のテストの限られた状況でのみ発生するよりも。

たとえば、AUTにログインすると、「USERとしてログインしました」というテキストが表示されるとします。単一のテストでこれを具体的に検証するのが適切ですが、なぜそれを検証したくないのでしょうか毎回ログインが呼び出されますか?このアーティファクトは、ページが「正しくロードされた」かどうかに直接関係しておらず、一般に「テスト対象」に関係していないため、上記のPOMガイドラインによれば、明らかにページメソッドに含めるべきではありません。 ..しかし、重要なアーティファクトを可能な限り頻繁に検証し、可能な限り少ない予見で自動化の力を最大化することは、明らかにそこにあるべきであるように思われます。検証コードをページメソッドに配置すると、テストで心配することなく、多くの検証を「無料」で取得できるため、自動化の力が倍増します。さまざまなコンテキストで頻繁に検証を行うと、多くの場合、見つけられない問題が見つかります。検証が、たとえば、そのアーティファクトの単一のテストに限定されている場合。

言い換えれば、私はテスト固有の検証と「一般的な」検証を区別する傾向があり、後者をページメソッドに(広範囲に)含めることは完全に適切/望ましいと思います。これにより、より薄いテストとより厚いページオブジェクトが促進されます。これらのガイドラインでは反対の競合がありますが、通常は増加より多くのコードを再利用することでテストの保守性が向上します。私は要点を逃していますか?ページメソッドで検証を望まない本当の理由は何ですか?私が説明した状況は、実際にはこれらのガイドラインで説明されている「例外」の1つであり、したがって実際にはPOMと矛盾していませんか?よろしくお願いします。 -jn-

34
Jon Nelson

ガイドラインとして、アサーションはページオブジェクトではなくテストで実行する必要があります。もちろん、これが実用的なアプローチではない場合もありますが、そのような場合は、上記のガイドラインが正しくなるほど頻繁ではありません。ページオブジェクトにアサーションを含めるのが嫌いな理由は次のとおりです。

  1. アサーションがページオブジェクトの他の場所に埋め込まれているverifyメソッドを呼び出すだけのテストを読むのは非常にイライラします。可能であれば、テストが何を主張しているのかを明確にする必要があります。これは、アサーションが直接テストにある場合に最もよく達成されます。テストの外のどこかにアサーションを隠すことにより、テストの意図はそれほど明確ではありません。

  2. ブラウザテストでのアサーションは高額になる可能性があります-それらはあなたのテストを本当に遅くする可能性があります。数百または数千のテストがある場合、テストの実行時間に分/時間を追加できます。これは悪いことです。アサーションをそれらの特定のアサーションを気にするテストだけに移動すると、はるかに迅速なテストが可能になり、関連する欠陥を見つけることができます。質問には次のものが含まれていました。

    ページメソッドに検証コードを配置すると、「無料」で多くの検証を取得できるため、自動化の能力が倍増します。

    さて、「自由は自由ではない」:)あなたが実際に掛けているのはあなたのテスト実行時間です。

  3. あちこちにアサーションがあると、別の良いガイドラインに違反します。 「テストごとに1つのアサーション」( http://blog.jayfields.com/2007/06/testing-one-assertion-per-test.html )。私はそれに固執しませんが、私は原則に従うようにしています。可能であれば、テストは1つのことだけに関心があるべきです。

  4. 1つのバグが原因で多数のテストが失敗し、テスト対象をテストできなくなるため、テストの価値が低下します。

    たとえば、AUTにログインすると、「USERとしてログインしました」というテキストが表示されるとします。単一のテストでこれを具体的に検証するのが適切ですが、ログインが呼び出されるたびに検証したくないのはなぜですか?

    ページオブジェクトクラスにアサーションがあり、予想されるテキストが変更された場合、ログインするallテストは失敗します。代わりにアサーションがテストに含まれている場合、1つのテスト(正しいメッセージを具体的にテストするテスト)のみが失敗し、他のすべてのテストは実行を継続して他のバグを見つけます。ログインメッセージが間違っていることを通知するために5,000回のテストは必要ありません。 1つのテストで十分です;)

  5. クラスに複数のことを行わせると、 [〜#〜] solid [〜#〜] の「S」に違反します。つまり、「 単一責任の原則 」(SRP)。クラスは1つのこと、そして1つのことだけに責任を持つべきです。この場合、ページオブジェクトクラスは、ページ(またはそのセクション)のモデリングのみを担当する必要があります。それ以上のことをする場合(例:アサーションを含む)、SRPに違反しています。

32
Nat Ritmeyer

私も時々この推薦に苦労しました。このガイドラインの背後にある理由は、ページオブジェクトを再利用可能に保つためであり、ページオブジェクト内にアサートを配置すると、多数の無関係なテストで再利用する機能が制限される可能性があると思います。とはいえ、ヘッダーのキャプションをテストするなど、ページオブジェクトに特定の検証方法を適用しました。私の経験では、変更されないページの要素のテストロジックをカプセル化するためのより良い方法です。

別の注意-ドメインモデルがページオブジェクトとして再利用されているMVCアプリケーションを見たことがあります。これを正しく行うと、テストライブラリの冗長なコードを大幅に減らすことができます。このパターンでは、ビューモデルはテストフレームワークを参照しないため、明らかに、ビューモデルにアサーションを配置することはできません。

10
Matt Mangold

ページオブジェクトはテストフレームワークについて認識している必要があるため、ページオブジェクトはアサーションを実行しないでください(組み込みの言語アサーションを使用している場合を除く)。ただし、ページは、要素を見つけてアクションを実行するために、その状態を知る必要があります。

重要なのは、「もちろん、すべてのガイドラインと同様に、例外があります...」というステートメントにあります。

ページは、アサーションを実行するのではなく、例外をスローする必要があります。そうすれば、テストでアサーションをキャッチして、それに応じて保釈または行動することができます。例えば。

page = ProfilePage.open
try 
  page.ChangePassword(old, new)
catch notLoggedIn
  page.Login(user, pass)

assert page.contains "your password has been updated"

この限られた例では、もう一度(そして何度も)チェックする必要があるため、最善の方法ではないかもしれませんが、アイデアは得られます。状態を確認することもできます(2回)

if page.hasLoginDialog
  page.Login

if page.hasLoginDialog //(again!)
  assert.fail("can't login")

プロフィールページがあることを確認することもできます

try 
  page = site.OpenProfilePage
catch notOnProfilePage

または、必要な要素がありますprofilepage.changePassword(old、new)catchelementNotFoundを試してください

または例外をスローせずに

page = site.OpenProfilePage
if ! page instanceof ProfilePage

または複雑なチェックで

assert page.looksLikeAProfilePage

重要なのはあなたがそれをどのように行うかではありません。テストのロジックを最小限に抑えたいが、ページオブジェクトをテストフレームワークに関連付けたくない-結局のところ、スクレイピングやデータ生成に同じオブジェクトを使用する可能性があります-または別のテストで独自のアサーションを持つフレームワーク。

必要を感じた場合は、アサーションをテストケースからテストヘルパーメソッドにプッシュできます。

page = site.GoToProfilePage
validate.looksLikeProfilePage(page)

あなたの言語がそれらをサポートしているなら、これはミックスインにとって素晴らしい機会です、それであなたはあなたのきれいなページオブジェクトを持つことができます-そしてあなたのサニティチェックをミックスインします。

6
fijiaaron

同じアサーションが複数のテストメソッドで使用される可能性があるのを見ると、これは私を困惑させます。たとえば、アサーション固有のメソッドを作成します-

public PaymentPage verifyOrderAmount(BigDecimal orderAmount) {      
   Assertion.assertEquals(lblOrderAmount.getText(), orderAmount, "Order Amount is wrong on Payment details page"); 
   return this; 
}

これで、必要なすべてのテストで再利用できます。複数のシナリオを扱う複数のテストで同じアサーションステートメントを繰り返す代わりに。言うまでもなく、テストに応じて、メソッド内で複数のアサーションをチェーンできます。

 .verifyOrderAmount(itemPrice)
 .verifyBankAmount(discountedItemPrice)
 .verifyCouponCode(flatDiscountCode.getCouponCode()) 

ページオブジェクトがページによって提供されるサービスを表すことになっている場合、アサーションポイントはページによって提供されるサービスでもありませんか?

4
Tarun

@Mattがページオブジェクトでドメインモデルを再利用することで時間を節約できるかもしれませんが、テストの匂いではありません。テストロジックはドメインモデルから十分に離れています(達成しようとしていることによって異なります)。

元の質問に戻ります。本当にページオブジェクトでアサーションを実行する必要がある場合は、isLoaded()メソッドを使用できるSelenium loadablecomponent <>を使用するか、loadablecomponent <>クラスにカスタムアサーションを含めることができます。これにより、ページオブジェクトにアサーションがなくなりますが、ロード可能なコンポーネントでアサーションを実行できます。以下のリンクを参照してください...

https://github.com/SeleniumHQ/Selenium/wiki/LoadableComponent

_夢想家

3
Dreamer