34

我为什么要使用@FindByvs driver.findElement()

@FindBy迫使我将所有变量移动到类级别(当大多数变量只需要在方法级别时)。它似乎给我买的唯一东西是 I can call PageFactory.initElements(),它为我处理延迟初始化。

我错过了什么?

4

6 回答 6

65

粗略地说,@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使得对元素的查找只发生一次。之后,它将被缓存在变量中并且可以更快地访问。

希望这可以帮助。有关更多详细信息,请务必检查PageFactoryPageObject 模式

于 2013-08-26T03:52:12.383 回答
2

我不喜欢 @FindBy 注释,因为 IntelliJ 不再检测是否正在使用该变量,因此清理起来很痛苦。

于 2018-02-22T16:08:37.930 回答
2

简而言之,两者@FindBy都是driver.findElement()通过不同Locator Strategies定位元素的不同方法。

使用 PageFactory 时,我们可以使用注解类型 FindBy。FindBy注释帮助我们删除了我们通常在查找元素时使用的样板代码。findElement()findElements()

举个例子:

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

变成:

element.click();

您可以在讨论如何使用 PageFactory 字段和 PageObject 模式的显式等待中找到@Simon Stewart 对同一主题的评论


参考

您可以在以下位置找到一些相关的详细讨论:

于 2019-01-18T10:10:47.843 回答
1

使用 Page Factory 的优点之一是,它可以避免StaleElementException。请参阅以下链接:

页面对象模型如何解决 StaleElementReferenceException?

以上链接摘录:

当我们使用页面对象设计模式时,您会看到程序运行良好。你永远不会得到过时的元素引用异常。当我们在 POM 中使用 FindBy 注解时,webdriver 会在每次对其执行任何操作之前定位元素并更新引用。您可以使用 web 元素而无需重新定位任何位置。这是使用页面对象模型的主要优势。


如何对抗和避免陈旧元素。

以上链接摘录:

如何对抗和避免陈旧元素

有很多方法可以在 Web 上处理 Stale Element Exception。在这里,我收集了我个人认为最有用的那些。

一个好的做法是使用 @FindBy 注释,因为延迟初始化这种方式元素将在实际使用之前被初始化。示例:@FindBy(xpath=”someXpath”) public WebElement someElement;

对 JavaScript、Ajax、Jquery 等使用等待方法。这将解决导致此异常发生的“竞争条件”。

于 2018-12-18T23:56:16.053 回答
0

我看到使用@FindBy 的另一个优势。当你在同一个类中有两个同名方法时,只返回不同的页面对象和传递的参数:driver。然后您可以在 PageObject 中使用:

public <T extends TestingEnvironment > T clickAction(Class<T> expectedPage){
            element.click();
            return PageFactory.initElements(driver, expectedPage);
        }

测试方法:

public void Test() {
        TestingEnvironment testingEnvironment = PageFactory.initElements(driver, TestingEnvironment.class);

        testingEnvironment.openPage();

        Patient patient = testingEnvironment.logIn();

        Reason reason = patient.clickAction(Reason.class);
        //You also can assing:
        NewReason newReason =  patient.clickAction(NewReason.class);

    }
于 2019-11-23T15:38:23.533 回答
-2
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

}`
于 2016-10-13T10:52:10.540 回答