In the previous tutorial, we have learned the first way to design and build the Selenium page object model design pattern using the normal approach for application under test (AUT). 

Now, in this tutorial, we will cover the second way to implement page object model design pattern using Page factory class of Selenium WebDriver API. The page object pattern brings the following advantages for your tests such as enhancing tests, making tests highly maintainable, reducing code duplication, building a layer of abstraction, and hiding the inner implementation from tests. 

What is Page Factory in Selenium?


Page Factory in Selenium is an inbuilt extension of Page Object Model but it is very optimized. It is a class where we use @FindBy annotation to find WebElement and initElementts() method to initialize web elements automatically. 

PageFactory class extends object class and It is present in org.openqa.selenium.support.PageFactory package. The syntax for Page Factory class is as follows:
Syntax:
         public class PageFactory
               extends java.lang.Object  

@FindBy Annotation


Page factory class provides several annotations to locate an element on the web page but the most common annotation is @FindBy annotation that is used to find elements using locators easily. @FindBy annotation can accept id, name, tagName, className, partialLinkText, linkText and advanced locator strategies like XPath, CSS selectors as attributes.

There are two syntaxes for @FindBy annotations that are as follows:
Syntax 1:
1. @FindBy(how = How.LocatorName, using = "Attribute value" )
     Access_ modifiersName  WebElement element;

Syntax 2:
2. @FindBy( LocatorName = "Attribute value")
     Access_modifiersName WebElement element;
Syntax of @FindBy in Page factory class
The functionality of two preceding examples are equivalent and both are correct. Which one you decide to use, it doesn't matter. Let's see an example related to these syntaxes.
1. @FindBy(how = how.NAME, using = "q" )
      private WebElement searchBox;
2. @FindBy(name = "q")
     private WebElement searchBox;

initElements() Method in PageFatcory class


The initElements() method of PageFactory class is used to initialize WebElements declared in the page class. It is a static method. That's why we call it using the class name. It is called inside a constructor that will automatically initialize all the elements in the page class when it is instantiated. The syntax for initElements() method is as follows:
Syntax:
    public static void initElements( WebDriver driver, Object page )
This method takes two input parameters such as driver object declared in the test and current object page. The keyword "this" is used to pass the current page object. It returns nothing.

The syntax to call initElements() method inside a constructor is as follows:
    public Class_Name( WebDriver driver ) { PageFactory.initElements( driver, this); }
When we initialize page's object (WebElements) using PageFactory class in the page class, the page factory class searches for the elements on the web page with id or name attribute matching with the name of WebElement object declared in the page class.

Creating Page Object Model using Page Factory in Selenium


Let's take a scenario in which we will implement page object model using page factory technique.
Scenario to Automate:
1. Launch the Firefox web browser.
2. Open Google home page "https://www.google.com".
3. Get the title of Google home page.
4. Send a text "Selenium" to the search box and click on the submit button.
5. Then, close the web browser.

Now, you will observe in the above scenario that we are dealing with one web page i.e. Home Page. Accordingly, we will create one page class and one test class. Follow the below steps to implement the Page Object Model Design Pattern by using Page factory approach.
Step 1: 
a. Create a package named com.googlesearch.page.
b. Create a class named "GoogleSearchPage" for Google home page to hold element locators and their methods. To execute both page class, we can create page objects for all available pages in the AUT. 

c. Declare a WebDriver reference variable in each page class.
d. For each page class, create a constructor and pass WebDriver as an input parameter. 
e. Inside a constructor, call initElements() method by using PageFactory object reference to initialize elements in the class. The initElements() method takes the driver object created in the test and initializes elements declared in the GoogleSearchPage class.

f. Locate all web elements using locators as done in the following source code.  We can reuse these locators in multiple methods so that maintenance will be easy. If any change happens in the UI in the future, we can simply update one Page.
g. Declare a method to perform operations on each web element in the class.

Let's understand the following source code related to page class.
Program source code 1:
    package com.googlesearch.page; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.How; import org.openqa.selenium.support.PageFactory; public class GoogleSearchPage { // Create a WebDriver reference variable. WebDriver driver; // Declare a constructor and pass WebDriver reference as an input parameter. public GoogleSearchPage( WebDriver driver ) { this.driver = driver; // Call initElements() method by using PageFactory reference and pass driver and this as parameters. PageFactory.initElements( driver, this); } // Locate all elements using locators in the home page. @FindBy(how = How.NAME, using = "q") WebElement searchBox; @FindBy(how = How.NAME, using = "btnK") WebElement submit; // Declare methods to perform operations on the elements. public void title() { String getTitle = driver.getTitle(); System.out.println("Title of Homepage: " +getTitle); } public void search() { searchBox.sendKeys("Selenium"); } public void submit() { submit.click(); } }
Steps 2:
a. Create another package named com.googlesearch.test.
b. Create a TestClass class. Here, we will create WebDriver object to launching the Firefox browser, maximize browser, implementing waits, launching URL and etc.

Let's see the following source code for the TestClass class.
Program source code 2:
    package com.googlesearch.test; import java.util.concurrent.TimeUnit; import org.openqa.selenium.WebDriver; import org.openqa.selenium.firefox.FirefoxDriver; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; import com.googlesearch.page.GoogleSearchPage; public class TestClass { static WebDriver driver; @BeforeTest public void setUp() { driver = new FirefoxDriver(); driver.manage().window().maximize(); String url = "https://www.google.com"; driver.get(url); driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); } @Test(priority = 0) public void googleSearch() { // Create an object of GoogleSearchPage class. GoogleSearchPage gs = new GoogleSearchPage(driver); gs.title(); // Calling title method. gs.search(); // Calling search method. gs.submit(); // Calling submit method. } @AfterTest public void closing() { TestClass.driver.quit(); } }
Step 3:
Now, create testng.xml file to run the above test script.
    <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="Suite"> <test name="Page Object Model Project"> <classes> <class name="com.googlesearch.test.TestClass" /> </classes> </test> <!-- Page Object Model Project --> </suite> <!-- Suite -->
On running this testng.xml file in the Eclipse, it will redirect to google.com web page in the Firefox browser. It will then perform all operations on the web elements on the home page. This is how Page Object Model can be implemented in the Selenium project using Page factory technique.

Let's look at a glance at the output of the above scenario.
    Output: Title of Homepage: Google =============================================== Suite Total tests run: 1, Failures: 0, Skips: 0 ===============================================
In this example, the GoogleSearchPage class defines the various method for loading, getting title of the home page, searching, and providing access to elements to the test. This makes test development easy by creating a layer of abstraction, hiding the internal details of web page, and exposing only operations and fields needed for testing from the page.

Final words
Hope that this tutorial has covered almost all important points related to Page factory class in Selenium WebDriver with practical example scenario. I hope that you will have understood @FindBy and initElements() method in this tutorial and enjoyed it.

Thanks for reading!