2

この 1 年間、私は自分のグループのために非常に優れた WebDriver フレームワークを構築しました。かなり標準的な運賃: 通常、ページ クラスは、プラットフォーム上のページの全機能をカプセル化します (By オブジェクトとしてのコントロール、必要に応じてメソッド) & いくつかのグローバル メソッドで基本クラスを拡張します。JUnit テスト クラス内で複数のページが呼び出され、典型的なアサーション メソッドです。 、ヤダヤダ。本のように贅沢なことは何もありませんが、非常に機能的で柔軟です。

しかし最近、フレームワークを使用して、100 以上の入力、選択、オプションなどを保持できるフォームを含む多数のページを自動化するよう依頼されました。さらに、多くのカスタム フォーム コントロールの id は環境ごとに変化します (幸いなことに、最初のプッシュの後、それらは環境ごとに静的なままです)。ともかく...

私が毎日使用する典型的な PageObject 構造を見てみましょう。

/** Constructor*/
public someConstructor(WebDriver driver){
   super(driver, pageTitle);
}

/**Locators*/
By searchBoxLocator = By.id("phSearchInput");
By searchBoxClearLocator = By.id("phSearchClearButton");
By searchButtonLocator = By.cssSelector("input[value='Search']");


/**Some Methods*/
public void selectFromTabBar(String tabName){
   driver.findElement(By.linkText(tabName)).click();
}

public static void enterInputValue(WebDriver driver, By by, String val){

   List<WebElement> elements = null;
   elements = driver.findElements(by);

   if(!elements.isEmpty()){
     driver.findElement(by)).sendKeys(val);     
   }else{
     throw new NoSuchElementException("Message");
   }
}

私が言ったように、ここで風変わりなことは何もありませんが、ここで皆さんへの私の質問です。PageObject ごとに従来の 5 ~ 15 By ではなく、10 の Pages に対して 100 を超える可能性がある状況を考えてみましょう。また、環境ごとに独自の値を持つことになるという複雑な問題を投げかけますが、これは完全に誰の手にも負えず、調整することはできません。それで、ここで適切なアプローチは何ですか...私は箇条書きを噛んでページごとに100インチのByをハードコードしますか、すべてのByをたとえばExcelドキュメントに外部化し、JXLなどを介してすべてをプルしますか、または静的であることがわかっているByをハードコーディングして、すべてを外部ファイルにスローしますか?

結局のところ、正解がないことはわかっていますが、他の人がこれにアプローチすることに興味があります。現在、非常に多くのフォーム要素を持ち、PageObject 内で変更されないコントロールを定義するページの By を外部化しましたが、扱いにくいと感じています。エレガンスを求めすぎているのかもしれませんが、どんな考えでも本当に素晴らしいと思います。

4

1 に答える 1

3

これは主に意見に基づくものですが、興味深い質問です。

私の提案は、ページをモジュール化することです。

たとえば、100 個のロケーターを含むページがあるとしますが、ユーザーが記入できるような 100 個の同様のテキスト ボックスにすることはできません。(そうであれば、おそらくここでの解決策は、最初に UI を再設計することです)

この 100 個の要素が異なるコンポーネントに属している場合、たとえば、上部のツールバーに 20 個の要素、リスト ビューに 20 個の要素、フォームに 20 個の要素、下部のツールバーに 20 個の要素があるとします。次に、コンポーネントごとに異なるクラスを作成することができます。

たとえば、これは通常のページ オブジェクトです。

public class FooPage {

    private IWebDriver driver;

    public FooPage(IWebDriver driver) {
         this.driver = driver;
    }

    public IWebElement Element1 {
         get { return driver.FindElement(By.CssSelector(".something1")); }
    }

    // ...
    public IWebElement Element100 {
         get { return driver.FindElement(By.CssSelector(".something100")); }
    }

    public void AddItem(){
    }

    public void ClearList(){
    }
}

FooPageTopToolbarこれらの要素を、FooPageList、 などのさまざまなコンポーネントに分けることができます。

public class FooPageTopToolbar {

    private IWebDriver driver;

    public FooPageTopToolbar(IWebDriver driver) {
         this.driver = driver;
    }

    // ...
    public IWebElement ToolbarElement10 {
         get { return driver.FindElement(By.CssSelector(".something100")); }
    }

    public void AddItem(){
    }
}

public class FooPageList {

    private IWebDriver driver;

    public FooPageList(IWebDriver driver) {
         this.driver = driver;
    }

    // ...
    public IWebElement ListElement10 {
         get { return driver.FindElement(By.CssSelector(".something100")); }
    }

    public void ClearList(){
    }
}

今、あなたは次のFooPageようになります

public class FooPage {

    private IWebDriver driver;

    public FooPage(IWebDriver driver) {
         this.driver = driver;
    }

    public FooPageTopToolbar {
         get { return new FooPageTopToolbar(driver); }
    }

    // other components as well
    public FooPageList {
         get { return new FooPageList(driver); }
    }
}

これは単なるデモであることに注意してください。ページ オブジェクトを構築するために、継承インターフェイス、および抽象化を含めることも検討してください。たとえば、TopToolbarが他の多くのページで共有されている場合、必要なクラスは 1 つだけです。異なるページに似ているがわずかに異なるツールバーがある場合は、ある種の抽象ツールバー クラスを作成します。

また、環境ごとに異なるロケーターがあるとおっしゃいましたが、私の意見では、要素識別子をソースコードに追加するのが最善の解決策です(「識別子」とは、識別可能な部分、おそらく HTML を意味しますが、テスト目的でid最も一般的には一意ですclass)。この場合、UI 開発者によって頻繁に変更されないテスト ロケーターのセットが 1 つだけ必要になります。

于 2014-01-20T03:48:08.070 に答える