web-dev-qa-db-ja.com

Selenium @FindBy vs driver.findElement()

なぜ_@FindBy_ vs driver.findElement()を使用する必要があるのですか?

_@FindBy_は、すべての変数をクラスレベルに移動することを強制します(ほとんどの変数がメソッドレベルである必要がある場合)。私を買うように思える唯一のものは、PageFactory.initElements()を呼び出すことができることです。

私は何が欠けていますか?

27
pyrrhicVictory

大まかに言うと、_@FindBy_は要素を見つけるための代替方法にすぎません(「通常の方法」はdriver.findElement()でした)。

ただし、このアノテーションの大きな利点はそれ自体ではありません。 PageObjectパターンをサポートするために使用する方が適切です。

簡単に言うと、PageObjectパターンは、システムの各ページにクラスを作成するよう指示します使用/テストしようとしています。

したがって、(通常のdriver.findElement()コード)の代わりに:

_public class TestClass {
    public void testSearch() {
        WebDriver driver = new HtmlUnitDriver();
        driver.get("http://www.google.com/");
        Element searchBox = driver.findElement(By.name("q"));
        searchBox.sendKeys("stringToSearch");
        searchBox.submit();
        // some assertions here
    }
} 
_

ページのクラスを定義します(使用する要素に_@FindBy_注釈を付けます):

_public class GooglePage {
    @FindBy(how = How.NAME, using = "q")
    private WebElement searchBox;
    public void searchFor(String text) {
        searchBox.sendKeys(text);
        searchBox.submit();
    }
}
_

そして次のように使用します:

_public class TestClass {
    public void testSearch() {
        WebDriver driver = new HtmlUnitDriver();
        driver.get("http://www.google.com/");
        GooglePage page = PageFactory.initElements(driver, GooglePage.class);
        page.searchFor("stringToSearch");
        // some assertions here
    }
} 
_

今、私はこれが最初は冗長に見えるかもしれませんが、少し時間を置いて、そのページのいくつかのテストケースを持つことを検討してください。 searchBoxの名前が変わったらどうなりますか? (name _"q"_からidへ、たとえばquery?と言います)

どのコードで、それを再び動作させるためにさらに変更がありますか?ページオブジェクト(および_@FindBy_)のあるものとないものページの構造が大幅に変更された場合、どのコードでメンテナンスが簡単になりますか?

次のような追加の注釈など、他にもいくつかの利点があります。

_@FindBy(name = "q")
@CacheLookup
private WebElement searchBox;
_

_@CacheLookup_は、要素の検索を一度だけ実行します。その後、変数にキャッシュされ、より速くアクセスできるようになります。

お役に立てれば。詳細については、PageFactoryおよびPageObjectパターン

55
acdcjunior

@FindByアノテーションは、IntelliJがその変数が使用されているかどうかを検出しなくなり、クリーンアップするのが面倒になるため、好きではありません。

3
1ak31sha

簡単に言えば、_@FindBy_とdriver.findElement()は両方とも、異なる Locator Strategies を通じて要素を見つけるための異なるアプローチです。

PageFactoryを使用する場合、 注釈タイプFindBy を使用できます。 FindBy注釈は、一般的に次の形式で使用するboiler-plateコードを削除するのに役立ちますfindElement()およびfindElements()要素を検索する場合。

例として:

_WebElement element = driver.findElement(By.name("q"));
element.click();
_

になる:

_element.click();
_

ディスカッション内の同じトピックに関する@Simon Stewartのコメントを見つけることができます PageFactoryフィールドとPageObjectパターンで明示的な待機を使用する方法

1
DebanjanB
import org.openqa.Selenium.WebElement;
import org.openqa.Selenium.support.FindBy;
public class CommonPageForStudent {

    @FindBy(name="usname")
    private WebElement Studentusername;
    @FindBy(name="pass")
    private WebElement Studentpassword;
    @FindBy(xpath="//button[@type='submit']")
    private WebElement StudentLetmein;
    @FindBy(id="logoutLink")
    private WebElement StudentlogoutLnk;
    public  void loginToStudent(String username , String password ){
        Studentusername.sendKeys(username);
        Studentpassword.sendKeys(password);
        StudentLetmein.click();

       }

    //when you call this methods from another class write this 2 line code that class
    //CommonPageForStudent page = PageFactory.initElements(driver,       CommonPageForStudent.class);
    // page.loginToStudent("","");

    public void logOut(){
        StudentlogoutLnk.click();
    }
    //page.logOut(); method call

}`
0

Page Factoryを使用する利点の1つは、StaleElementExceptionを回避できることです。以下のリンクをご覧ください:

ページオブジェクトモデルがStaleElementReferenceExceptionを解決する方法

上記のリンクからの抜粋:

ページオブジェクトデザインパターンを使用すると、プログラムが正常に実行されます。古い要素参照の例外は発生しません。 POMでFindByアノテーションを使用すると、webdriverはエレメントを見つけ、アクションを実行する前に毎回参照を更新します。どこでも再配置せずにWeb要素を使用できます。これは、ページオブジェクトモデルを使用する主な利点です。


古い要素との戦いと回避方法

上記のリンクからの抜粋:

古くなった要素と戦い、回避する方法

Web上の古い要素の例外を処理する方法はたくさんあります。ここで、私が個人的に最も役に立つと思うものを集めました。

遅延初期化のために@FindByアノテーションを使用することをお勧めします。これにより、実際の使用の直前に要素が初期化されます。例:@FindBy(xpath =” someXpath”)public WebElement someElement;

JavaScript、Ajax、Jqueryなどの待機メソッドを使用します。これにより、この例外が発生する「レース状態」が解決されます。

0