Why should I use @FindBy
vs driver.findElement()
?
@FindBy
forces me to move all my variables to a class level (when most of them only need to be at the method level). The only thing it seems to buy me is I can call PageFactory.initElements()
, which handles lazy initialization for me.
What am I missing?
Roughly speaking, @FindBy
is just an alternate way of finding elements (the "usual way" being driver.findElement()
as you said).
The big advantage of that annotation is not itself, though. It is better used to support the PageObject pattern.
In a few words, the PageObject pattern tells you to create a class for each page of the system you are trying to use/test.
So, instead of having (the usual driver.findElement()
code):
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
}
}
You'd define a class for the page (with the @FindBy
annotation for the elements used):
public class GooglePage {
@FindBy(how = How.NAME, using = "q")
private WebElement searchBox;
public void searchFor(String text) {
searchBox.sendKeys(text);
searchBox.submit();
}
}
And use it like:
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
}
}
Now, I know this may seem verbose at first, but just give it a moment and consider having several tests cases for that page. What if the name of the searchBox
changes? (From the name
"q"
to an id
, say query
?)
In what code there would be more changes to make it work again? The one with or the one without the Page Objects (and @FindBy
)? If a page changes its structure a lot, in what code the maintenance would be easier?
There are some other advantages, such as additional annotations like:
@FindBy(name = "q")
@CacheLookup
private WebElement searchBox;
That @CacheLookup
makes the lookup for the element happen just once. After that, it will be cached in the variable and accessible much faster.
Hope this helps. For more details, make sure to check PageFactory and the PageObject pattern.
I don't like @FindBy annotations because then IntelliJ no longer detects if that variable is being used, makes it a pain to clean up.
In simple words, both @FindBy
and driver.findElement()
are different approach to locate element/s through different Locator Strategies.
When using PageFactory we can use the Annotation Type FindBy. The FindBy annotations helps us to remove the boiler-plate code which we generally use in the form of findElement()
and findElements()
when looking for elements.
As an example:
WebElement element = driver.findElement(By.name("q"));
element.click();
becomes:
element.click();
You can find @Simon Stewart's comments on the same topic within the discussion How to use explicit waits with PageFactory fields and the PageObject pattern
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
}`
One of the advantages of using Page Factory is, it can avoid StaleElementException. Please see the below link:
How Page Object Model solves StaleElementReferenceException?
Excerpts from the above link:
You will see programs run fine when we use page object design pattern. You will never get Stale Element Reference Exception. When we use FindBy annotation in POM, webdriver locates element and update reference every time before performing any action on that. You can use web element without relocating any where. This is major advantage of using Page Object Model.
How to fight and avoid Stale Elements.
Excerpts from the above link:
How to fight and avoid Stale Elements
There are many ways of dealing with Stale Element Exception on the web. Here I gathered the ones that I personally find most useful.
A good practice is to use @FindBy annotation because of Lazy Initialization This way elements will be initialized right before actual usage. Example: @FindBy(xpath=”someXpath” ) public WebElement someElement;
Use wait methods for JavaScript, Ajax, Jquery etc. This will solve the “Race condition” that causes this exception to occur.
来源:https://stackoverflow.com/questions/18436102/selenium-findby-vs-driver-findelement