Building the test framework:
test automation patterns
Test automation basics with Selenium & Java
By:
Evgeny Novikov
Email:
xevgnov@[Link]
PageObject
By:
Evgeny Novikov
Email:
xevgnov@[Link]
Test class now
@Test
public void searchByKeywordSeleniumHaveToFindSeleniumhqOrgInTop() {
WebElement searchField = [Link](By. id("lst-ib"));
[Link]( "Selenium");
[Link](Keys. RETURN);
List<WebElement> resultURLs =
[Link](By. xpath("//cite[@class='iUh30']"));
assertThat([Link]( 0).getText()).as( "[Link] is
not the first result!").contains( "[Link] By:
Evgeny Novikov
} Email:
xevgnov@[Link]
Page Object
Patterns helps us to resolve problems:
● reduce code duplication
● improve readability
● improve maintainability
Page Object is needed for:
● code reuse - one page will be used in several tests
● defines allowed actions on the page By:
● separating elements and actions Evgeny Novikov
Email:
xevgnov@[Link]
What is worth to use with page object:
1) @FindBy annotations
2) Page Factory pattern.
Let’s refactor the framework and
create package ‘pages’ with classes:
● SearchPage
● SearchResult
By:
● abstract BasePage Evgeny Novikov
Email:
xevgnov@[Link]
Page object pages
package pages;
public class SearchPage extends BasePage {
package pages;
public class SearchResultPage extends BasePage{
package pages;
public abstract class BasePage { By:
Evgeny Novikov
} Email:
xevgnov@[Link]
Provide access to WebDriver
public abstract class BaseTest {
private static WebDriver driver;
public static WebDriver getDriver(){
return driver;
By:
Evgeny Novikov
Email:
xevgnov@[Link]
Use driver on BasePage
public class BasePage {
protected WebDriver driver;
public BasePage()
[Link] = BaseTest. getDriver();
} By:
Evgeny Novikov
} Email:
xevgnov@[Link]
Search page - version 1
public class SearchPage extends BasePage {
private By searchFieldBy = [Link]("lst-ib");
public SearchPage(){ super();}
public void fillTheSearchField(String keyword) {
WebElement searchField = [Link]( searchFieldBy);
[Link](keyword); }
public void pressEnter() {
WebElement searchField = [Link]( searchFieldBy);
[Link](Keys. RETURN);} By:
Evgeny Novikov
}} Email:
xevgnov@[Link]
Search results page - version 1
public class SearchResultPage extends BasePage {
private By searchResultURLsBy =
[Link]("//cite[@class='iUh30']");
public SearchResultPage(){ super();}
public void assertThatExpectedValueIsOnSearchTop(String
expectedValue) {
List<WebElement> searchResultURLs =
[Link]( searchResultURLsBy);
assertEquals([Link]( 0).getText(),
"expectedValue", expectedValue + " is not the first result!");
By:
} Evgeny Novikov
Email:
} xevgnov@[Link]
@FindBy annotations in Page Object
● allows to declare WebElement
● replace findElement/findElements
Instead of
WebElement clearButton = [Link]([Link]( "clear"));
there is
@FindBy(id = "clear")
WebElement clearButton;
By:
Evgeny Novikov
Email:
xevgnov@[Link]
Search page - version 2
public class SearchPage extends BasePage {
@FindBy(id = "lst-ib")
private WebElement searchField;
public SearchPage(){ super();}
public void fillTheSearchField(String keyword) {
[Link](keyword); }
public void pressEnter() {
[Link](Keys. RETURN);} By:
Evgeny Novikov
} Email:
xevgnov@[Link]
Search results page - version 2
public class SearchResultPage extends BasePage {
@FindBy(xpath = "//cite[@class='iUh30']")
private List<WebElement> searchResultURLs;
public SearchResultPage(){ super();}
public void assertThatExpectedValueIsOnSearchTop(String
expectedValue) {
assertEquals([Link](0).getText(),
"expectedValue", expectedValue + " is not the first result!");
} By:
Evgeny Novikov
} Email:
xevgnov@[Link]
@FindBy problems
WebElements should be initialized only before their usage to
avoid NoSuchElementException.
Solution:
1) BaseTest extends PageFactory
2) [Link](driver, this);
By:
Evgeny Novikov
Email:
xevgnov@[Link]
Changes on BasePage
public class BasePage {
WebDriver driver;
public BasePage()
[Link] = BaseTest. getDriver();
PageFactory. initElements(driver, this);
}
By:
} Evgeny Novikov
Email:
xevgnov@[Link]
Steps & Chain of
invocations
By:
Evgeny Novikov
Email:
xevgnov@[Link]
Steps pattern
The additional layer: business logic
1. defines possible actions on each page
- steps
- verifications
2. encapsulates work on web page
3. binds the pages
By:
Evgeny Novikov
Email:
xevgnov@[Link]
Steps pattern implementation - SearchSteps
public class SearchSteps {
private SearchPage searchPage = new SearchPage();
public SearchResultsSteps searchByKeyword(String keyword){
[Link](keyword);
[Link]();
return new SearchResultsSteps();
By:
} Evgeny Novikov
Email:
} xevgnov@[Link]
Steps pattern implementation - SearchResultSteps
public class SearchResultsSteps {
private SearchResultsPage searchResultsPage = new SearchResultsPage();
public SearchResultsSteps verifyThatTopValueIsCorrect(String expectedValue) {
[Link](expectedValue);
return this;
}
By:
} Evgeny Novikov
Email:
xevgnov@[Link]
Steps pattern implementation - BaseTest
SearchSteps steps;
//steps variable can be initialized in some @Before method, like below:
@BeforeClass
public void setUp() {
// some code here
steps = new SearchSteps();
By:
Evgeny Novikov
Email:
xevgnov@[Link]
@Test method with Steps pattern
@Test
public void searchByKeywordSeleniumHaveToFindSeleniumhqOrgInTop() {
[Link]("Selenium")
.verifyThatTopValueIsCorrect("[Link]
By:
Evgeny Novikov
Email:
xevgnov@[Link]
Extend test described in the
presentation:
1) use the same scenario with
doSearchWithKeyword("Selenium")
- do search in Google
2) add new verification step:
Exercise Verify that all search results on
the page actually contains
Add new step
keyword “Selenium”
Use List <WebElement>
elements;