我为什么要使用@FindBy
vs driver.findElement()
?
@FindBy
迫使我将所有变量移动到类级别(当大多数变量只需要处于方法级别时)。它似乎唯一给我买的是我可以调用PageFactory.initElements()
,它为我处理延迟初始化。
我错过了什么?
答案 0 :(得分:49)
粗略地说,@FindBy
只是寻找元素的另一种方式(正常方式是driver.findElement()
,如你所说)。
然而,该注释的最大优势本身并非如此。它最好用于支持 PageObject pattern 。
简而言之, 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 pattern 。
答案 1 :(得分:3)
我不喜欢@FindBy注释,因为IntelliJ不再检测是否正在使用该变量,这使得清理很麻烦。
答案 2 :(得分:1)
简单地说,@FindBy
和driver.findElement()
都是通过不同的Locator Strategies来定位元素的不同方法。
使用PageFactory时,我们可以使用Annotation Type FindBy。 FindBy 注释可帮助我们删除在查找元素时通常以findElement()
和findElements()
形式使用的样板代码。
例如:
WebElement element = driver.findElement(By.name("q"));
element.click();
成为:
element.click();
您可以在讨论How to use explicit waits with PageFactory fields and the PageObject pattern
中找到@Simon Stewart对同一主题的评论答案 3 :(得分:0)
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
}`
答案 4 :(得分: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);
}
答案 5 :(得分:-1)
使用Page Factory的优点之一是,它可以避免 StaleElementException 。 请参见以下链接:
How Page Object Model solves StaleElementReferenceException?
上述链接的摘录:
当我们使用页面对象设计模式时,您将看到程序运行良好。 您将永远不会获得Stale Element Reference Exception。当我们使用 通过POM中的FindBy注释,Webdriver可以定位元素并进行更新 每次对它执行任何操作之前都要进行引用。您可以使用 Web元素,而无需将其放置在任何位置。这是主要优势 使用页面对象模型。
How to fight and avoid Stale Elements.
上述链接的摘录:
如何战斗和避免陈旧元素
有许多方法可以处理 网络。在这里,我收集了我个人认为最有用的内容。
由于懒惰,一种好的做法是使用@FindBy注释 初始化这样,元素将在之前被初始化 实际使用情况。示例:@FindBy(xpath =“ someXpath”)public WebElement someElement;
对JavaScript,Ajax,Jquery等使用等待方法。这将解决 导致此异常发生的“种族条件”。