我为什么要使用@FindBy
vs driver.findElement()
?
@FindBy
迫使我将所有变量移动到类级别(当大多数变量只需要在方法级别时)。它似乎给我买的唯一东西是 I can call PageFactory.initElements()
,它为我处理延迟初始化。
我错过了什么?
我为什么要使用@FindBy
vs driver.findElement()
?
@FindBy
迫使我将所有变量移动到类级别(当大多数变量只需要在方法级别时)。它似乎给我买的唯一东西是 I can call PageFactory.initElements()
,它为我处理延迟初始化。
我错过了什么?
粗略地说,@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 模式。
我不喜欢 @FindBy 注释,因为 IntelliJ 不再检测是否正在使用该变量,因此清理起来很痛苦。
简而言之,两者@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 对同一主题的评论
您可以在以下位置找到一些相关的详细讨论:
使用 Page Factory 的优点之一是,它可以避免StaleElementException。请参阅以下链接:
页面对象模型如何解决 StaleElementReferenceException?
以上链接摘录:
当我们使用页面对象设计模式时,您会看到程序运行良好。你永远不会得到过时的元素引用异常。当我们在 POM 中使用 FindBy 注解时,webdriver 会在每次对其执行任何操作之前定位元素并更新引用。您可以使用 web 元素而无需重新定位任何位置。这是使用页面对象模型的主要优势。
如何对抗和避免陈旧元素。
以上链接摘录:
如何对抗和避免陈旧元素
有很多方法可以在 Web 上处理 Stale Element Exception。在这里,我收集了我个人认为最有用的那些。
一个好的做法是使用 @FindBy 注释,因为延迟初始化这种方式元素将在实际使用之前被初始化。示例:@FindBy(xpath=”someXpath”) public WebElement someElement;
对 JavaScript、Ajax、Jquery 等使用等待方法。这将解决导致此异常发生的“竞争条件”。
我看到使用@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);
}
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
}`