Selenium:@FindByおよびPageFactoryを使用してページ要素を操作する

この記事では、@ FindByアノテーションを使用してページ上の要素を検索する方法、およびフォームやテーブルなどの要素やコンテナーを操作するための独自のクラスを作成する可能性について説明します。



@FindByの概要



最初に、ya.ruでフレーズを検索するだけのテストを見てみましょう。

public class SearchTest { @Test(dataProvider = "pageObjects") public void testSearch(final SearchPage searchPage) { searchPage.init(driver); driver.get("http://ya.ru"); searchPage.search("Bolek i Lolek"); } @DataProvider private Object[][] pageObjects() { return new Object[][]{ {new SimpleSearchPage()}, {new AnnotatedSearchPage()}, {new ExtendedSearchPage()}, {new SearchPageWithSearchForm()} }; } private WebDriver driver; @BeforeClass public void beforeClass() { driver = new FirefoxDriver(); } @AfterClass public void afterClass() { driver.quit(); } }
      
      





ご覧のとおり、テストは非常に単純で実際には何もテストしません。@ FindByの学習の進化を考慮して、異なるページオブジェクトで4回だけ開始します。

最初は、検索ページのページクラスは次のようになりました。

 public class SimpleSearchPage implements SearchPage { private WebDriver driver; @Override public void search(final String query) { driver.findElement(By.id("text")).sendKeys(query); driver.findElement(By.cssSelector("input[type=\"submit\"]")).click(); } @Override public void init(final WebDriver driver) { this.driver = driver; } }
      
      





ここでは、Webドライバーを使用して要素を検索するための非常に標準的なアプローチ、つまり driver.findElement(By.something())。

手首を軽く振ると、注釈を使用してこのクラスを変換できます

 public class AnnotatedSearchPage implements SearchPage { @FindBy(id = "text") private WebElement searchField; @FindBy(css = "input[type=\"submit\"]") @CacheLookup private WebElement searchButton; @Override public void search(final String query) { searchField.sendKeys(query); searchButton.click(); } @Override public void init(final WebDriver driver) { PageFactory.initElements(driver, this); } }
      
      





どのように機能しますか?! init()メソッドで、 PageFactory.initElements(driver, this);



を呼び出しPageFactory.initElements(driver, this);



。 ドライバーはすぐにページ上の要素の検索を開始しませんが、クラスフィールドにアクセスするとすぐに要素を検索します。 たとえば、文字列searchButton.click();



driver.findElement(By.cssSelector("input[type=\"submit\"]")).click();





このアプローチの利点は十分ではないようですが、次のとおりです。

  1. driver.findElements(...)を記述し、クラス全体にこの検索をコピーアンドペーストする必要はありません。
  2. @CacheLookupアノテーションを使用できます。最初に要素が見つかったとき、ドライバーはそれをキャッシュし、将来キャッシュされたオブジェクトを既に使用します。これにより、テストの速度がわずかに向上します。
  3. WebElementインターフェースの使用をやめて、Button、TextFieldなどのページ要素用の独自のクラスを作成できます。


ページ要素のカスタムクラスを作成する



WebElementインターフェースがあまり便利ではないという事実に繰り返し遭遇しました。

  1. セレンテストでは絶対に不要な.getCssValue()などの冗長機能を提供します。
  2. 展開することはできません。 非常に便利なメソッドを毎日2つ追加することはできません。したがって、不要なメソッドを削除することはできません(たとえば、.isEnabled()メソッドが意味をなさないリンクの場合)。
  3. より複雑な要素(ドロップダウンリストなど)を操作するには、Selectクラスのコンストラクターを明示的に呼び出す必要があります。これは、ある種のハックのようなものです。


ページ上の要素のインターフェイスを使用してページクラスを変更する方法を見てみましょう。

 public class ExtendedSearchPage implements SearchPage { @FindBy(id = "text") private TextField searchField; @FindBy(css = "input[type=\"submit\"]") private Button searchButton; @Override public void search(final String query) { searchField.clearAndType(query); searchButton.click(); } @Override public void init(final WebDriver driver) { PageFactory.initElements(new ExtendedFieldDecorator(driver), this); } }
      
      





そのため、ここではWebElementの代わりにTextFieldとButtonをすでに使用しています。 ここで重要なのは、init()メソッドで自己記述型FieldDecoratorを使用することです。 現在、ExtendedSearchPageクラスのフィールドを初期化するのは彼です。 このアプローチを使用する長所:

  1. テストの可読性が向上しました。フィールドのタイプを見ると、これはボタンであり、ページ上の一部の抽象的な要素ではなく、ボタンであることがすぐに明らかになります。
  2. 入力フィールドのclearAndType()など、独自のメソッドを追加する機能。
  3. コンテナクラス(テーブル、フォームなど)を作成するよりエレガントな方法。


もちろんマイナスがあります。見つかった要素ごとに、メモリ内に別のオブジェクトが作成され、WebElementオブジェクトへのすべての呼び出しが単に委任されます。



コンテナクラスの作成



いつものように、始めるための小さなコード

 public class SearchPageWithSearchForm implements SearchPage { @FindBy(tagName = "form") private SearchForm searchForm; @Override public void search(final String query) { searchForm.search(query); } @Override public void init(final WebDriver driver) { PageFactory.initElements(new ExtendedFieldDecorator(driver), this); } } public class SearchForm extends AbstractContainer { @FindBy(id = "text") private TextField searchField; @FindBy(css = "input[type=\"submit\"]") private Button searchButton; public void search(final String query) { searchField.clearAndType(query); searchButton.click(); } }
      
      





ここには、検索フォーム用の本格的なクラスが既にあります。これは異なるページで簡単に再利用できます(もちろん、検索フォームがサイトのすべてのページに等しく実装されている場合)。 さらに、要素の検索がページ全体ではなくコンテナ内でのみ行われるようにコンテナオブジェクトを初期化するプロセスを実装できます。したがって、コンテナは世界について何も知らないことがわかり、最終的に使用する機会が与えられます他のページのテスト用。



ソースコード


サンプルソースはこちらからダウンロードできます



All Articles