Suppose you have an online shopping website, it has a lot of web pages. Two of the most important are login page and index page. It is very easy to write test automation script to implement login action. You just need to open login page, input username and password in correct input text box, then click submit. After that you also need to check whether your login success or not.
Example Java Code for Login feature without POM
@Test /* Test login feature automatically without pom. */ public void testLoginWithoutPom() throws InterruptedException { /* Go to local login.html demo web page. */ this.ffDriver.get("file://C:/WorkSpace/dev2qa.com/Code/src/com/dev2qa/webdriver/pom/login.html"); /* Check whether we open the correct page or not by page title. */ By byXPathLoginPageTitle = By.xpath("/html/head/title"); WebElement loginPageTitleWebEle = this.ffDriver.findElement(byXPathLoginPageTitle); /* Get page title text. */ String loginPageTitle = loginPageTitleWebEle.getAttribute("innerHTML"); Assert.assertEquals(loginPageTitle, "Login to dev2qa.com demo system"); /* Find user name input text box. */ By byIdUsername = By.id("UserName"); WebElement userNameWebEle = this.ffDriver.findElement(byIdUsername); /* Input username. */ userNameWebEle.sendKeys("Jerry"); /* Find password input text box. */ By byIdPassword = By.id("Password"); WebElement passwordWebEle = this.ffDriver.findElement(byIdPassword); /* Input password. */ passwordWebEle.sendKeys("123456"); /* Find submit button. */ By byIdSubmit = By.id("submitBtn"); WebElement submitWebEle = this.ffDriver.findElement(byIdSubmit); /* Click to submit the form. */ submitWebEle.click(); Thread.sleep(3000); /* Check whether go to index.html correctly or not. */ By byXPathIndexPageTitle = By.xpath("/html/head/title"); WebElement indexPageTitleWebEle = this.ffDriver.findElement(byXPathIndexPageTitle); /* Get page title text. */ String indexPageTitle = indexPageTitleWebEle.getAttribute("innerHTML"); Assert.assertEquals(indexPageTitle, "Index page of dev2qa.com demo system"); Thread.sleep(3000); }
Html code for the example
login.html
<title>Login to dev2qa.com demo system</title> </head> <body> <form action="index.html" method="post"> User Name : <input type="text" value="" id="UserName"/><br/> Password : <input type="password" value="" id="Password"/><br/> <input type="submit" value="Login" id="submitBtn"/><input type="reset" value="Clear" id="resetBtn"/> </form>
index.html
<title>Index page of dev2qa.com demo system</title> </head> <body> You have login to dev2qa.com demo system successfully. </body>
Problem
But you have also other pages such as shopping cart, order list and what ever pages that need login first. So how to write all those test cases in test automation script? Will you copy and paste the login action automation script code into every test case’s automation script? Off course, the answer is No. Because we all know that is so inefficiency. If the login web element changed then you need to change java code in every test script.
What is POM
Page Object Model also called POM is the solution to resolve such problem. It encapsulate a web page, the web elements in it and the actions take place on the web element into a java Object.
The POM java class maps to the web page, the java class instance variable maps to the web elements and the instance method maps to actions take place in the page.
POM Advantages
- Each web page in your web site will relate to a java class. This class’s variables and methods will map to all the web elements and business logic actions in the page. It even include method to verify web element’s value.
- The java classes are reusable. It is separate from automation test cases. They can be reused in multiple automation test cases.
- Test script code becomes short and efficiency. Code change is very easy using POM classes.
- Method name is more meaningful. You can easily know what business operation is from the method name. For example, if the method name is loginToWebsite that means this method is responsible for login action.
Write test script using POM
Now we will rewrite the test script at the article’s beginning use POM. Below is the java file structure and java code.
Java file structure
./ ├── com │ └── dev2qa │ └── webdriver │ ├── pom │ │ ├── TestLoginFeatureWithoutPom.java │ │ ├── index.html │ │ ├── login.html │ │ ├── pages │ │ │ ├── Dev2qaIndexPage.java │ │ │ └── Dev2qaLoginPage.java │ │ └── test │ │ └── TestDev2qaLogin.java
Dev2qaLoginPage map to login.html
public class Dev2qaLoginPage { /* Webdriver object is used to operate web element in login.html . */ private WebDriver webDriver = null; /* Map to username input text field. */ private By userName = By.id("UserName"); /* Map to password input text field. */ private By password = By.id("Password"); /* Map to submit button. */ private By submitBtn = By.id("submitBtn"); /* Map to reset button. */ private By resetBtn = By.id("resetBtn"); /* Map to login.html's title. */ private By pageTitle = By.xpath("/html/head/title"); /* Login page class constructor. The parameter is transfered from out side where call this class.*/ public Dev2qaLoginPage(WebDriver webDriver) { this.webDriver = webDriver; } /* Set username value in username input box.*/ private void setUserName(String userNameValue) { this.webDriver.findElement(userName).sendKeys(userNameValue); } /* Set password value in password input box.*/ private void setPassword(String passwordValue) { this.webDriver.findElement(password).sendKeys(passwordValue); } /* This method implements login button click action. */ private void clickLoginButton(){ this.webDriver.findElement(submitBtn).click(); } /* Get the return page title. */ public String getLoginPageTitle(){ return this.webDriver.findElement(pageTitle).getAttribute("innerHTML"); } /* This method encapsulate all the logic for a login action.*/ public void loginToDev2qa(String strUserName,String strPasword){ /* Set username value to username text box. */ this.setUserName(strUserName); /* Set password value to password text box. */ this.setPassword(strPasword); /* Click button to submit the form.*/ this.clickLoginButton(); } }
Dev2qaIndexPage map to index.html
public class Dev2qaIndexPage { /* Webdriver object is used to operate web element in index.html. */ private WebDriver webDriver = null; /* Map to index.html's title. */ private By indexPageTitle = By.xpath("/html/head/title"); /* Index page class constructor.*/ public Dev2qaIndexPage(WebDriver webDriver) { this.webDriver = webDriver; } /* Return index.html's title. */ public String getIndexPageTitle(){ return this.webDriver.findElement(this.indexPageTitle).getAttribute("innerHTML"); } }
TestDev2qaLogin is the new login test case
public class TestDev2qaLogin { private static WebDriver ffDriver = null; Dev2qaLoginPage loginPage = null; Dev2qaIndexPage indexPage = null; @BeforeClass /* Initiate the Firefox Driver object. */ public static void Setup() { if(ffDriver==null) { ffDriver = new FirefoxDriver(); /* Maximize the Firefox browser window. */ ffDriver.manage().window().maximize(); } } @AfterClass /* Quit the webdriver object and close web browser after all the test runs. */ public static void quitBrowser() { if(ffDriver != null) { /* Quit and close Firefox browser. */ ffDriver.quit(); } } @Test /* Test feature automatically with pom. */ public void testLoginWithoutPom() throws InterruptedException { /* Go to local login.html demo web page. */ this.ffDriver.get("file://C:/WorkSpace/dev2qa.com/Code/src/com/dev2qa/webdriver/pom/login.html"); this.loginPage = new Dev2qaLoginPage(this.ffDriver); String loginPageTitle = this.loginPage.getLoginPageTitle(); Assert.assertEquals(loginPageTitle, "Login to dev2qa.com demo system"); this.loginPage.loginToDev2qa("dev2qa.com", "dev2qa.com"); Thread.sleep(3000); this.indexPage = new Dev2qaIndexPage(this.ffDriver); /* Check whether go to index.html correctly or not. */ String indexPageTitle = this.indexPage.getIndexPageTitle(); Assert.assertEquals(indexPageTitle, "Index page of dev2qa.com demo system"); Thread.sleep(3000); } }
What is Page Factory
Page Factory is a builtin feature that selenium webdriver provide for you to write POM java page class quickly and easily.
Mapping class variable to web element is easy when use @FindBy annotation in Page Factory. This annotation can take following attributes (id, name, tagName, linkText, partialLinkText, xpath, css, className).
/* Map to username input text field. */ @FindBy(id="UserName") private WebElement userName; /* Map to login.html's title. */ @FindBy(xpath="/html/head/title") private WebElement pageTitle;
PageFactory.initElements method will initialize all the web elements in the web page then you can use the web element directly in your java test code.
If we want to use Page Factory to rewrite above example again. We just need to change two java classes, we do not need to change test case script class. Below is the java code for Login page and Index page classes.
Java File Structure
./ ├── com │ └── dev2qa │ └── webdriver │ ├── pom │ │ ├── pagefactory │ │ │ ├── Dev2qaIndexPage.java │ │ │ └── Dev2qaLoginPage.java │ │ ├── pages │ │ │ ├── Dev2qaIndexPage.java │ │ │ └── Dev2qaLoginPage.java │ │ └── test │ │ └── TestDev2qaLogin.java
Dev2qaLoginPage.java
public class Dev2qaLoginPage { /* Webdriver object is used to operate web element in login.html page. */ private WebDriver webDriver = null; /* Map to username input text field. */ @FindBy(id="UserName") private WebElement userName; /* Map to password input text field. */ @FindBy(id="Password") private WebElement password; /* Map to submit button. */ @FindBy(id="submitBtn") private WebElement submitBtn; /* Map to reset button. */ @FindBy(id="resetBtn") private WebElement resetBtn; /* Map to login.html's title. */ @FindBy(xpath="/html/head/title") private WebElement pageTitle; /* login.html page class constructor. The parameter is transfered from out side where call this class.*/ public Dev2qaLoginPage(WebDriver webDriver) { this.webDriver = webDriver; /* This page factory method will initialize all the web elements.*/ PageFactory.initElements(webDriver, this); } /* Set username value in username input box.*/ private void setUserName(String userNameValue) { this.userName.sendKeys(userNameValue); } /* Set password value in password input box.*/ private void setPassword(String passwordValue) { this.password.sendKeys(passwordValue); } /* This method implements login.html page button click action. */ private void clickLoginButton(){ this.submitBtn.click(); } /* Get the return login.html's title. */ public String getLoginPageTitle(){ return this.pageTitle.getAttribute("innerHTML"); } /* This method encapsulate all the logic for a login action.*/ public void loginToDev2qa(String strUserName,String strPasword){ /* Set username value to username text box. */ this.setUserName(strUserName); /* Set password value to password text box. */ this.setPassword(strPasword); /* Click button to submit the form.*/ this.clickLoginButton(); } }
Dev2qaIndexPage.java
public class Dev2qaIndexPage { /* Webdriver object is used to operate web element in login.html. */ private WebDriver webDriver = null; /* Map to login.html's title. */ @FindBy(xpath="/html/head/title") private WebElement indexPageTitle; /* Index page class constructor.*/ public Dev2qaIndexPage(WebDriver webDriver) { this.webDriver = webDriver; PageFactory.initElements(webDriver, this); } /* Return index.html's title. */ public String getIndexPageTitle(){ return this.indexPageTitle.getAttribute("innerHTML"); } }