Wednesday, July 2, 2014

Page Object Model (POM)

Creating Selenium test cases can result in an unmaintainable project. One of the reasons is that too many duplicated code is used. Duplicated code could be caused by duplicated functionality and this will result in duplicated usage of locators. The disadvantage of duplicated code is that the project is less maintainable. If some locator will change, you have to walk through the whole test code to adjust locators where necessary. By using the page object model we can make non-breakable test code and reduce or eliminate duplicate test code. Beside of that it improves the readability and allows us to create interactive documentation. Last but not least, we can create tests with less keystroke. An implementation of the page object model can be achieved by separating the abstraction of the test object and the test scripts.
Steps to follow:
1. Create a New Package’ file and name it as pageObjects’, by right click on the Project and select New > Package. We will be creating different packages for Page Objects, Utilities, Test Data, Test Cases and Modular actions. It is always recommended to use this structure, as it is easy to understand, easy to use and easy to maintain.
2. Create a New Class’ file and refer the name to the actual page from the test object, by right click on the above created Package and select New > Class. In our case it is Login Page and Home Page.
3. Now create a Static Method for each Element (Object) in the Login Page. Each method will have an Argument (driver) and a Return value (element).
package pageObjects;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

public class Login_Page {
        private static WebElement element = null;

    public static WebElement txtbx_UserName(WebDriver driver){
         element = driver.findElement(By.id("TxtEmail"));
         return element;
         }
     public static WebElement txtbx_Password(WebDriver driver){
         element = driver.findElement(By.id("TxtPassword"));
         return element;
         }
     public static WebElement btn_Login(WebDriver driver){
         element = driver.findElement(By.id("BtnLogin"));
         return element;
         }
}
Driver is being passed as an Argument so that Selenium is able to locate the element on the browser (driver).
Element is returned, so that an Action can be performed on it.
Method is declared as Public Static, so that it can be called in any other method without instantiate the class.
Follow the same rule for creating Home Page class.
package pageObjects;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

public class Home_Page {
       private static WebElement element = null;
       public static WebElement btn_Paybills(WebDriver driver){
       element = driver.findElement(By.id("aBillListToPay"));
       return element;
       }

       public static WebElement lnk_LogOut(WebDriver driver){
              element = driver.findElement(By.xpath("//*[@id='divHeader']/UL[1]/LI[1]/UL[1]/LI[3]/A[1]"));
              return element;
       }
}
4. Create a New Class and name it as PageObjectModel by right click on the ‘automationFramework‘ Package and select New > Class. We will be creating all our test cases under this package.
package automationFramework;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import pageObjects.Home_Page;
import pageObjects.Login_Page;

public class PageObjectModel {
private static WebDriver driver = null;
public static void main(String[] args) {
driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("ApplicationURL");

// Use page Object library now
Login_Page.txtbx_UserName(driver).sendKeys("testuser_1@gmail.com");
Login_Page.txtbx_Password(driver).sendKeys("Test@123");
Login_Page.btn_Login(driver).click();
System.out.println(" Login Successfully.");
Home_Page.btn_Paybills(driver).click();
Home_Page.lnk_LogOut(driver).click();
driver.quit();
}
}
You will notice that once you type Login_Page in your test script and the moment you press dot, all the methods in the Login Page will be displayed. We can expose methods in order to reduce duplicated code. We are able to call these method multiple times. This will ensure a better maintainable test code, because we only have to make adjustments and improvements in one particular place.

Selenium Automation Framework - Introduction


Introduction 
Automating frameworks and maintaining quality software releases are critical to business performance. Enterprises often face the dilemma of balancing costs and managing resources to ensure that automation frameworks cover all the business scenarios and the applications delivered are error – free. By implementing the appropriate automated testing framework, enterprises can significantly increase the speed and accuracy of the testing process, provide a higher return on investment (ROI) from software projects and systematically minimize risk.

A framework defines the organization’s way of doing things – a ‘Single Standard’. Following this standard would result in the project team achieving.

Script-less representation of Automated tests: 
The testing framework should offer point-and-click interface for accessing and interacting with the application components under test—as opposed to presenting line after line of scripting. Testers should be able to visualize each step of the business scenario, view and edit test cases intuitively. This will shorten the learning curve for testers and help QA teams meet deadlines.

Data driven tests: 
A key benefit of automating functional testing is the ability to test large volumes of data on the system quickly. But you must be able to manipulate the data sets, perform calculations, and quickly create hundreds of test iterations and permutations with minimal effort. Test Automation Frameworks must have capability to integrate with spreadsheets and provide powerful calculation features.

Concise Reporting: 
The ability to run high volume of tests is of little benefit if the results of the tests are not easy to understand. The framework must automatically generate reports of the test run and show the results in an easy-to-read format. The reports should provide specifics about where application failures occurred and what test data was used. Reports must present application screenshots for every step to highlight any discrepancies and provide detailed explanations of each checkpoint pass and failure. Reports must also be easily shared across the entire QA and development teams.

Standard scripting and Team consistency: 
Scripting standard should be maintained across the framework library creation, which includes business components, system communications, data check points, loggers, reporters etc. Project team should follow the defined scripting standards. Published standards across the project team prevent the effort involved in duplicate coding, which prevent individuals from following their own coding standards.

Implement and Maximize re-usability: 
Establish the developed libraries across the organization/project team/product team i.e. publish the library and provide access rights. Utilities/components shared across the team. Usage of available libraries. Minimized effort for repeated regression cycle.

Friday, June 20, 2014

TestNG DataProviders



When you need to pass complex parameters or parameters that need to be created from Java (complex objects, objects read from a property file or a database, etc…), in such cases parameters can be passed using Dataproviders. A Data Provider is a method annotated with @DataProvider. A Data Provider returns an array of objects.
Let us check out the Login example using Dataproviders.

Steps to follow:
1)  Define the method credentials() which is defined as a DataProvider using the annotation. This method returns array of object array.
2) Add a method testLogin() to your DataProviderTest class. This method takes two strings as input parameters.
3) Add the annotation @Test(dataProvider = “Authentication”) to this method. The attribute dataProvider is mapped to “Authentication”.

Test will look like this:

package automationFramework;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class DataProviderTest {
            private static WebDriver driver;
           
  @DataProvider(name = "Authentication")
  public static Object[][] credentials() {
        return new Object[][] { { "testuser_1", "Test@123" }, { "testuser_2", "Test@111" }};
  }
 
  // Here we are calling the Data Provider object with its Name
  @Test(dataProvider = "Authentication")
  public void testLogin(String sUsername, String sPassword) {
              driver = new FirefoxDriver();
      driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
      driver.get("http://www.gmail.com");
      driver.findElement(By.id("txtUsername")).sendKeys(sUsername);
      driver.findElement(By.id("txtPassword")).sendKeys(sPassword);
      driver.findElement(By.id("btnLogin")).click();
      driver.findElement(By.xpath(".//*[@id='account_logout']/a")).click();
      driver.quit();
  }
}

Run the test by right click on the test case script and select Run As > TestNG Test. Give it few minutes to complete the execution and as the test data is provided two times, the above test will be executed two times completely.