Part 5: Hybrid Framework Development…

This is the final post on Hybrid Framework Development. Here we will focus on different reports and logs that will be created after running our test.

  • Before running our test, our ‘HybridFramework’ project structure will be displayed as below.

    HybridFramework Project Structure
  • We have 3 source folders, JRE System Library and Maven Dependencies, src and target folder, pom.xml file in our project.
  • Here we will execute using Chrome browser. For that we just need to update the property <selenium.browser>CHROME</selenium.browser> inside our pom.xml file.
  • After updating the pom.xml file, we have to ensure that the properties are updated in system.properties file inside ‘src/main/resources‘ source folder. Right click on ‘HybridFramework’ project and select Maven -> Update Project as displayed below.

    Update Project
  • After successful update, we can verify the same in system.properties file.

    system.properties file
  • Next task is to execute our test. Right click on ‘HybridFramework’ project and click Run As -> Maven Test.
  • The test gets successfully completed and we can see that two tests are executed. The Logs are printed in console as well as in a log file.

    System Console
  • Refresh the project once we can see three more folders are created – RESULT_LOG, Screenshots, and test-output.

    Output folders
  • The RESULT_LOG folder contains the Extent Report. As displayed below this HTML report has all the actions captured. Also as we coded in the action methods, screenshots are attached too. This report not only looks good but also share vital information of our test.

    Extent Report
  • The Screenshots folder stores all captured screenshots inside the project folder. This framework also ensures that the folders and reports are created based on execution date.

    Reported created based on execution date
  • The test-output folder contains not only the regular TestNG reports but also the log file of our execution. If we execute as Maven Test, the test-output folder will contain only the log file. Notice that we configured the log folder name and the log file name inside Log4j.xml.

    Log file creation
  • The log file once opened will be displayed as below. Notice that it will capture all the log information as we coded inside Page Objects.

    Sample of log file

 

With this, we completed our Hybrid Framework Development. This framework can be successfully implemented for web-based projects that are planning to move from manual QA to Automation QA. This framework takes a modular approach and is very easy to maintain. Apart from that it also creates wonderful reports that can be shared across different teams.

In coming posts, we will cover on how to upload our project into a repository and then execute using CI tool. Sounds interesting, right?

Well, for that you need to keep following. Till then, Happy Learning!

The complete project is available on GitHub in below location:
https://github.com/autotestmadness/HybridFramework

Part 4: Hybrid Framework Development…

This post is the continuation of Hybrid Framework Development. For a complete understanding of Hybrid Framework Development, please go through the previous posts on Hybrid Framework Development.

Part 1: Hybrid Framework Development…
Part 2: Hybrid Framework Development…
Part 3: Hybrid Framework Development…

In this post, we will be creating a TestNG script. We will create two tests, although the flow is same we will use a different set of test data.

First Test Case: Navigate to New Tours application and perform a successful login. Search for a one-way flight departing from London on 7th.

Second Test Case: Navigate to New Tours application and perform a successful login. Search for a one-way flight departing from Paris on 10th.

  • Right click on the ‘src/test/java‘ folder and click New -> Package. Name the package as ‘com.testmadness.testcase’ and click Finish to close the window.
  • Inside ‘com.testmadness.testcase’ package, we will place our TestNG class. Right click on ‘com.testmadness.testcase’ package and select TestNG -> Create TestNG class. Name the class as ‘BookFlightTest.java’. Copy the below code into ‘BasePage.java’ file.
    package com.testmadness.testcase;
    
    import org.testng.annotations.Test;
    import com.testmadness.pages.HomePage;
    import com.testmadness.utils.Config;
    import com.testmadness.utils.Constants;
    import com.testmadness.utils.ExcelUtil;
    import com.testmadness.utils.Log;
    import com.testmadness.utils.Reports;
    import org.testng.annotations.BeforeMethod;
    import java.lang.reflect.Method;
    import org.apache.log4j.xml.DOMConfigurator;
    import org.openqa.selenium.WebDriver;
    import org.testng.annotations.AfterMethod;
    import org.testng.annotations.BeforeClass;
    
    public class BookFlightTest {
    	WebDriver driver;
    	HomePage homePage;
    	Reports report;
    	
      // First Test Case	
      @Test
      public void firstTestCase() {
    	  homePage = new HomePage(driver);
    	  try {
    		homePage.navigateToURL(ExcelUtil.getCellData(1, 1));
    		homePage.loginUser(ExcelUtil.getCellData(1, 2), ExcelUtil.getCellData(1, 3)).findFlights(ExcelUtil.getCellData(1, 4), ExcelUtil.getCellData(1, 5));
    	} catch (Exception e) {
    		e.printStackTrace();
    	} 
      }
      
      //Second Test Case	 
      @Test
      public void secondTestCase() {
    	  homePage = new HomePage(driver);
    	  try{
    		  homePage.navigateToURL(ExcelUtil.getCellData(2, 1));
    		  homePage.loginUser(ExcelUtil.getCellData(2, 2), ExcelUtil.getCellData(2, 3)).findFlights(ExcelUtil.getCellData(2, 4), ExcelUtil.getCellData(2, 5));
    	  }catch (Exception e) {
    			e.printStackTrace();
    		}  
      }
      
      // Before Method to start logging
      @BeforeMethod
      public void beforeMethod(Method method) {
    	  
              // Passing the test case method name
    	  Log.startTestCase(method.getName());
    	  report.startTest(method.getName());
    	  System.out.println(Config.getProp().getProperty("selenium.browser")); 
      }
      
      // After Method to end logging
      @AfterMethod
      public void afterMethod() {
    	    homePage.endTest();
    	    homePage.endReport();
    	    Log.endTestCase("firstTestCase");
    	  
      }
      
      //Before Class to initialize Log4j
      @BeforeClass
      public void beforeClass() {
    	    System.setProperty(Config.getProp().getProperty("logfoldername"), Constants.logFolderName);
    	    System.setProperty(Config.getProp().getProperty("logfilename"), Constants.logFileName);
    	    DOMConfigurator.configure("src/main/java/com/testmadness/utils/log4j.xml");
    	    try {
    		   ExcelUtil.setExcelFile(Constants.PATH_DATA, "Sheet1");
    		} catch (Exception e) {
    		   e.printStackTrace();
    		}
    		 report = new Reports();
    	}	
    }
    
  • In the above code we have used two ‘@Test’ methods for our two test cases. We have set the path of our test data sheet and completed the Log4j configuration in ‘@BeforeClass’ method. In ‘@BeforeMethod’ we started the Extent Report and Log4j logging. In ‘@AfterMethod’, we stopped the logging as well as closed the test.
  • After successful completion till here, our project will look like as displayed below.

    ‘src/test/java’ folder
  • We can create as many as test scripts using TestNG class. More details are on Part 1: Scripting using TestNG….

With this we completed the scripting part inside our Hybrid Framework. We automated two test cases. In the next post we will go through the reporting and logging which is going to be an interesting topic. Till then, Happy Learning!

 

Part 3: Hybrid Framework Development…

This post is a continuation of Part 1: Hybrid Framework Development… and Part 2: Hybrid Framework Development…

Here we will mainly focus on creating Page Objects of our Demo website as well as use the Page Factory concepts.

For better understanding, please go through the following posts:

Part 1: Page Object Model…
Part 2: Page Object Model…
Working with Page Factory…

  • Our first task is to create a Base class. This Base class will have common methods that will be used in all our Page Object classes. Right click on the ‘src/main/java‘ folder and click New -> Package. Name the package as ‘com.testmadness.base’ and click Finish to close the window.
  • Inside ‘com.testmadness.base’ package, we will place our Base class. Right click on ‘com.testmadness.utils’ package and select New -> Class. Name the class as ‘BasePage.java’. Copy the below code into ‘BasePage.java’ file.
    package com.testmadness.base;
    
    import java.io.File;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.concurrent.TimeUnit;
    import org.apache.commons.io.FileUtils;
    import org.openqa.selenium.NoSuchElementException;
    import org.openqa.selenium.OutputType;
    import org.openqa.selenium.TakesScreenshot;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.WebElement;
    import org.openqa.selenium.chrome.ChromeDriver;
    import org.openqa.selenium.chrome.ChromeOptions;
    import org.openqa.selenium.firefox.FirefoxDriver;
    import org.openqa.selenium.safari.SafariDriver;
    import org.openqa.selenium.support.PageFactory;
    import org.openqa.selenium.support.ui.ExpectedConditions;
    import org.openqa.selenium.support.ui.Select;
    import org.openqa.selenium.support.ui.WebDriverWait;
    import com.relevantcodes.extentreports.LogStatus;
    import com.testmadness.utils.Config;
    import com.testmadness.utils.Constants;
    import com.testmadness.utils.Log;
    import com.testmadness.utils.Reports;
    
    public class BasePage {
    	
    	public WebDriver driver;
    	private static final int pageElementLoadWait = 30;
    	private static final int pageTimeOutWait = 20;
    	public Reports report = new Reports();
    	public static HashMap<WebElement, String> elementDetails = new HashMap<WebElement, String>();
    	
    	public BasePage(WebDriver driver){
    	    this.driver = driver;
    		if(driver==null){
    			driver = getDriver();	
    		}
    		//Initialize Page Factory. Passing child object
    		PageFactory.initElements(driver, this);
    		Log.info("Page Factory initialized");
    		
    	}
    	
            // Driver Initialization
    	public WebDriver getDriver(){
    		
    		String browser = Config.getProp().getProperty("selenium.browser");
    		
    		if(browser.equals("SAFARI")){
    			System.setProperty("webdriver.safari.driver", Config.getProp().getProperty("webdriver.safari.driver"));
    			driver = new SafariDriver();
    			driver.manage().window().maximize();
    		}
    		else if(browser.equals("FIREFOX")){
    			System.setProperty("webdriver.gecko.driver", Config.getProp().getProperty("webdriver.firefox.driver"));
    			driver = new FirefoxDriver();
    			driver.manage().window().maximize();
    			driver.manage().timeouts().implicitlyWait(pageTimeOutWait, TimeUnit.SECONDS);
    		}
    		else if(browser.equals("CHROME")){
    			System.setProperty("webdriver.chrome.driver", Config.getProp().getProperty("webdriver.chrome.driver"));
    			ChromeOptions options = new ChromeOptions();
    			options.addArguments("--start-maximized");
    			options.addArguments("--disable-web-security");
    			options.addArguments("--no-proxy-server");
    			Map<String, Object> prefs = new HashMap<String, Object>();
    			prefs.put("credentials_enable_service", false);
    			prefs.put("profile.password_manager_enabled", false);
    			options.setExperimentalOption("prefs", prefs);
    			driver = new ChromeDriver(options);
    			driver.manage().timeouts().implicitlyWait(pageTimeOutWait, TimeUnit.SECONDS);
    		}
    		
    //Setting page load time out		driver.manage().timeouts().pageLoadTimeout(pageTimeOutWait, TimeUnit.SECONDS);
    		return driver;
    	}
    	
    	// Wait for Element to be clickable
    	public WebElement waitForElement(WebElement element) {
    		try{
    			WebDriverWait wait = new WebDriverWait(driver, pageElementLoadWait);
    			wait.until(ExpectedConditions.elementToBeClickable(element));
    			Log.info("Wait for element "+ elementDetails.get(element));
    			return element;
    		}catch(Exception e){
    			
    		}
    		return null;
    	}
    	
    	// Navigate to URL
    	public void navigateToURL(String siteURL) {
    		driver.navigate().to(siteURL);
    		report.logStatus(LogStatus.PASS, "OpenBrowser: " + Config.getProp().getProperty("selenium.browser") + "," + siteURL,
    				"Passed");
    		Log.info("Demo URL Launched");
    	}
    	
    	// Take a screenshot
    	public void takeScreenShot(String fileName) {
    		try {
    			File screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
    			FileUtils.copyFile(screenshot, new File(Constants.sScreenshotFilepath + fileName + ".jpeg"));
    			Log.info("Screenshot captured");
    		} catch (Exception e) {
    			System.out.println(e.getMessage());
    			Log.info("Screenshot exception");
    		}
    	}
    	
    	// End Extent Reporting
    	public void endReport() {
    		report.endTest();
    	}
    	
    	// End a Test
    	public void endTest() {
    		driver.close();
    		driver.quit();
    	}
    	
    	/*Click Element method.
    	This method will log in Extent Report as well in Log4j.*/
    	public boolean clickElement(WebElement element) {
    		try {
    			element = waitForElement(element);
    			if (element != null) {
    				takeScreenShot(elementDetails.get(element));
    				report.logStatus(LogStatus.PASS, "Click",
    						"Click " + elementDetails.get(element) + " Success");
    				report.screenshotLog(LogStatus.PASS, "Click Success " + elementDetails.get(element),
    						Constants.sScreenshotFilepath + elementDetails.get(element) + ".jpeg");
    				Log.info("Element Clicked: "+elementDetails.get(element));
    				element.click();
    				return true;
    			}
    			else
    				throw new NoSuchElementException("Element not found");
    		} catch (Exception e) {
    			takeScreenShot("Fail_" + Constants.dateTag);
    			report.screenshotLog(LogStatus.FAIL, "Click Failed ",
    					Constants.sScreenshotFilepath + "Fail_" + Constants.dateTag + ".jpeg");
    			Log.info("Element Click Exception");
    			report.endTest();
    			throw new NoSuchElementException("Element not found");
    		}
    	}
    	
    	/*Enter text in text box method.
    	This method will log in Extent Report as well in Log4j.*/
    	public boolean EnterText(WebElement element, String input) {
    		try {
    			element = waitForElement(element);
    			if (element != null) {
    				element.sendKeys(input);
    				report.logStatus(LogStatus.PASS, "Enter Text",
    						"Enter Text into " + elementDetails.get(element) + " Success");
    				Log.info("Enter text: " + elementDetails.get(element));
    				return true;
    			}else
    				throw new NoSuchElementException("Element not found");
    		} catch (Exception e) {
    			takeScreenShot("Fail_" + Constants.dateTag);
    			report.screenshotLog(LogStatus.FAIL, "Enter Text",
    					Constants.sScreenshotFilepath + "Fail_" + Constants.dateTag + ".jpeg");
    			Log.info("Enter text Exception");
    			throw new NoSuchElementException("Element not found");
    		}	
    	}
    	
    	/*Select a value from drop down by text method.
    	This method will log in Extent Report as well in Log4j.*/
    	public boolean SelectElementByText(WebElement element, String input) {
    		try {
    			element = waitForElement(element);
    			if (element != null) {
    				Select dropdown = new Select(element);
    				dropdown.selectByVisibleText(input);
    				report.logStatus(LogStatus.PASS, "Select Element", "Select Element For " + elementDetails.get(element)
    						+ " Success");
    				Log.info("Select element: " + elementDetails.get(element));
    				return true;
    			}else
    				throw new NoSuchElementException("Element not found");
    		} catch (Exception e) {
    			takeScreenShot("Fail_" + Constants.dateTag);
    			report.screenshotLog(LogStatus.FAIL, "Select Element",
    					Constants.sScreenshotFilepath + "Fail_" + Constants.dateTag + ".jpeg");
    			Log.info("Select element Exception ");
    			throw new NoSuchElementException("Element not found");
    		}
    	}
    }
    
  • The above ‘BasePage’ class file has a constructor which creates an instance of the Page Object using ‘PageFactory’ class. It also has a method to initialize the required WebDriver, wait for an element to be clickable, navigate to an URL, take a screenshot and end the test. It also contains different action methods like clicking a web element, entering a text in a text box, selecting a value from a drop down. The action methods not only completes an action on a web element but also logs the information in the report and log file. Notice that we are declaring a HashMap (Collection in Java) public static HashMap<WebElement, String> elementDetails = new HashMap<WebElement, String>(); to store and name the web elements. We will use it to name the screenshot images.
  • Next task is to create Page Objects. Here we will create two Page Objects. This is similar to what we covered in Part 1: Page Object Model…. Right click on the ‘src/main/java‘ folder and click New -> Package. Name the package as ‘com.testmadness.pages’ and click Finish to close the window. Inside ‘com.testmadness.pages’ package, we will place our Page Objects.
  • Right click on ‘com.selenium.pages’ package and click New -> Class. Name the class as ‘HomePage.java’. This ‘HomePage’ class will extend our ‘BasePage’ class. In this class, we will place all the Home Page element locators and methods. Click Finish to close the window. Copy and paste below code into ‘HomePage’ class.
    package com.testmadness.pages;
    
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.WebElement;
    import org.openqa.selenium.support.FindBy;
    import com.testmadness.base.BasePage;
    import com.testmadness.utils.Log;
    
    public class HomePage extends BasePage {
    	
    	
    	public HomePage(WebDriver driver) {
    		super(driver);
    		
    	}
    
    	// Element Locators for username textbox
    	@FindBy(name = "userName")
    	private WebElement userName;
    	public WebElement getUserName(){
    		try{
                            // Store and name the web element into HashMap
    			elementDetails.put(userName, "User Name text box");
    		}catch(Exception e){
    			
    		}
    		return userName;
    	}
    
    	// Element Locators for password textbox
    	@FindBy(name = "password")
    	private WebElement password;
    	public WebElement getPassword(){
    		try{
                            // Store and name the web element into HashMap
    			elementDetails.put(password, "Password text box");
    		}catch(Exception e){
    			
    		}
    		return password;
    	}
    
    	// Element Locators for login button
    	@FindBy(xpath = "//input[@name='login']")
    	private WebElement login;
    	public WebElement getLogin(){
    		try{
                            // Store and name the web element into HashMap
    			elementDetails.put(login, "Login button");
    		}catch(Exception e){
    			
    		}
    		return login;
    	}
    
    	// Login method. Notice there is no return type
    	public FlightFinderPage loginUser(String uname, String pwd) {
    		// Enter username
    		EnterText(getUserName(), uname);
    		// Log4j logging
    		Log.info("HomePage.loginUser - username entered");
    
    		// Enter password
    		EnterText(getPassword(), pwd);
    		// Log4j logging
    		Log.info("HomePage.loginUser - password entered");
    
    		// Click Login button
    		clickElement(getLogin());
    		// Log4j logging
    		Log.info("HomePage.loginUser - login button clicked");
    	
                    // Returns an object of FlightFinderPage class
    		return new FlightFinderPage(driver);
    	}
    }
    
  • We will create one more Page Object. Right click on ‘com.selenium.pages’ package and click New -> Class. Name the class as ‘FlightFinderPage.java’. All our Page Object will extend the ‘BasePage’ class. Copy and paste below code into ‘FlightFinderPage’ class.
    package com.testmadness.pages;
    
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.WebElement;
    import org.openqa.selenium.support.FindBy;
    import com.testmadness.base.BasePage;
    import com.testmadness.utils.Log;
    
    
    public class FlightFinderPage extends BasePage {
    
    	public FlightFinderPage(WebDriver driver) {
    		super(driver);
    	}
    
    	//Element Locators for one way radio button
    	@FindBy(xpath = "//input[@value='oneway']")
    	private WebElement onewayRadio;
    
    	public WebElement getOneWayRadio() {
    		try {
                            // Store and name the web element into HashMap
    			elementDetails.put(onewayRadio, "One Way radio button");
    		} catch (Exception e) {
    
    		}
    		return onewayRadio;
    	}
    	
    	//Select the location from dropdown
    	@FindBy(name = "fromPort")
    	private WebElement fromPortDrop;
    	public WebElement getFromPortDrop(){
    		try{
                            // Store and name the web element into HashMap
    			elementDetails.put(fromPortDrop, "From Port drop down");
    		}catch (Exception e) {
    
    		}	
    		return fromPortDrop;
    	}
    	
    	//Select the day from dropdown
    	@FindBy(xpath = "//select[@name='fromDay']")
    	private WebElement fromDayDrop;
    	public WebElement getFromDayDrop(){
    		try{
                            // Store and name the web element into HashMap
    			elementDetails.put(fromDayDrop, "From Day drop down");
    		}catch (Exception e) {
    
    		}
    		return fromDayDrop;
    	}
    	
    	//Click Business radio button
    	@FindBy(xpath = "//input[@value='Business']")
    	private WebElement businessRadio;
    	public WebElement getBusinessRadio(){
    		try{
                            // Store and name the web element into HashMap
    			elementDetails.put(businessRadio, "Business radio button");
    		}catch (Exception e) {
    
    		}
    		return businessRadio;
    	}
    	
    	//Click find flights button
    	@FindBy(name = "findFlights")
    	private WebElement findFlightsButton;
    	public WebElement getFindFlightsButton(){
    		try{
                            // Store and name the web element into HashMap
    			elementDetails.put(findFlightsButton, "Find Flights button");
    		}catch (Exception e) {
    
    		}
    		return findFlightsButton;
    	}
    
    
    	//Find Flights method. Notice there is no return type
    	public void findFlights(String departFrom, String departDate) {
    		// Click one way radio button
    		clickElement(getOneWayRadio());
    		Log.info("FlightFinderPage.findFlights - One way Radio Button clicked");
    		// Select Departing From dropdown
    		SelectElementByText(getFromPortDrop(), departFrom);
    		Log.info("FlightFinderPage.findFlights - Depart From Dropdown clicked");
    
    		// Select Departing Day dropdown
    		SelectElementByText(getFromDayDrop(), departDate);
    		Log.info("FlightFinderPage.findFlights - Depart Date Dropdown clicked");
    
    		// Click business class
    		clickElement(getBusinessRadio());
    		Log.info("FlightFinderPage.findFlights - Business Radio Button clicked");
    
    		// Click Find Flights button
    		clickElement(getFindFlightsButton());
    		Log.info("FlightFinderPage.findFlights - Find Flights Button clicked");
    
    	}
    
    }
    
  • Our next task is to add the data sheet using which we will input the test data to our test scripts. We will take the same approach as we did in Data Driven Framework Development….
  • Right click on the ‘src/main/java‘ folder and click New -> Package. Name the package as ‘com.testmadness.data’ and click Finish to close the window. Inside the ‘com.testmadness.data’ package, we will place our test data file in ‘xlsx’ format. Always remember to format all cells in the excel sheet to text format. Our test data sheet will look as displayed below.

    Data.xlsx file for storing test data
  • This is how our ‘src/main/java‘ folder look like once we reach here.

    ‘src/main/java’ folder

With this, we have completed the creation of Page Objects. Here we created only two Page Objects. Best practice is to create one Page Object per page in the test application.

In the next post, we will be creating actual scripts in our Hybrid Framework. Till then, Happy Learning!

Part 2: Hybrid Framework Development…

In Part 1: Hybrid Framework Development…, we have created overall structure of our framework. Our next step is to create source codes inside our project. Here also we will take a step by step approach in creating the source code.

  • First, delete the unwanted packages from the ‘src/main/java‘ and ‘src/test/java’ folders. Remember, Maven by default creates some test classes. In our case, we don’t need them as we will be creating our own.
  • Right click on the ‘src/main/java‘ folder and click New -> Package. Name the package as ‘com.testmadness.utils’ and click Finish to close the window.
  • Inside ‘com.testmadness.utils’ package, we will place all the utility classes which are basically common classes and not project specific. For example, we need some class for the Log4j, Extent Reports, accessing the property file etc..
  • First of all, we will create a ‘Constants.java’ file to store all the constant values. Right click on ‘com.testmadness.utils’ package and select New -> Class. Name the class as ‘Constants.java’. Copy the below code into ‘Constants.java’ file. In this class, we will be storing different constants that will be referred from different classes. Notice that all our constants are static variables.
    package com.testmadness.utils;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class Constants {
    
    	// TestResults folder location
    	public static final String PATH_RESULTS = System.getProperty("user.dir") + "/TestResults/";
    
    	// Test Data Excel location
    	public static final String PATH_DATA = System.getProperty("user.dir") + "/src/main/java/com/testmadness/data/Data.xlsx";
    
    	// Test Data Excel Sheet name
    	public static final String SHEETNAME = "Sheet1";
    
    	// Test Data Excel File Name
    	public static final String FILE_NAME = "TestData.xlsx";
    
    	// Property file name
    	public static final String PROP_NAME = "system.properties";
    
    	// Property file location
    	public static final String PROP_LOCATION = "src/main/resources";
    
    	public static Date date = new Date();
    	public static SimpleDateFormat reportDate = new SimpleDateFormat("MM-dd-yyyy hh-mm-ss");
    	
    	//Log Files Constants
    	
    	public static String logFileName = "LOG_"+reportDate.format(date);
    	public static String dateTag = reportDate.format(date);
    	public static String logFolderName = "LOG_FOLDER_"+reportDate.format(date);
    
    	// Extent Report constants
    	public static final String filePath = System.getProperty("user.dir");
    	public static final String reportPath = filePath + "/RESULT_LOG";
    	public static final String imagePath = filePath + "/IMAGES";
    
    	public static final String reportFileName = reportPath + "/" + "TESTREPORT_" + reportDate.format(date) + "TC.html";
    	public static final String screenshotFileName = reportPath + "/SCREENSHOTS" + "TESTREPORT_"
    			+ reportDate.format(date) + "TC.html";
    	public static final String screenshotFilePath = screenshotFileName + "/SCREENSHOTS" + "TEST"
    			+ reportDate.format(date) + "/";
    	public static String sScreenshotFilepath = filePath + "/Screenshots/" + "IOLS_Screenshot_" + reportDate.format(date)
    			+ "/";
    	public static String sReportFileName = reportPath + "/" + "IOLSTestReport_" + reportDate.format(date) + ".html";
    
    }
    
  • Next, we will create a class to access the property file. Right click on ‘com.testmadness.utils’ package and select New -> Class. Name the class as ‘Config.java’. Copy the below code into ‘Config.java’ file.
    package com.testmadness.utils;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.InputStream;
    import java.util.Properties;
    
    public class Config {
    
    	private static Properties prop;
    	public static Properties getProp() {
    		if (prop == null) {
    			prop = new Properties();
    			InputStream input = null;
    			try {
    				//Two arguments passed for property file location
    				input = new FileInputStream(new File(Constants.PROP_LOCATION, Constants.PROP_NAME));
    				prop.load(input);
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
    		}
    		return prop;
    	}
    }
    
  • Next, we will create Log class and log4j.xml files. We can directly copy the codes from Working with Log4j logging…. We need only codes from’Log.java‘ and ‘log4j.xml‘ files. Notice that both these files will be placed inside ‘com.testmadness.utils’ package. However ‘log4j.xml‘ file has small changes in order to get the log folder and log files names. Copy the below code and copy in ‘log4j.xml‘ file.
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
    <log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
    	<!-- Appender for printing in console -->
    	<appender name="console" class="org.apache.log4j.ConsoleAppender">
    		<layout class="org.apache.log4j.PatternLayout">
    		    <!-- %d{yyyy-MM-dd HH:mm:ss} refers to Date format 2017-03-23 15:54:44 INFO  Log:15 -->
    		    <!-- %-5p refers to Type of logging INFO-->
    		    <!-- %c{1}  -->
    			<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
    		</layout>
    	</appender>
    	<!-- Appender for printing in file -->
    	<appender name="file" class="org.apache.log4j.RollingFileAppender">
    		<!-- Appending false -->
    		<param name="append" value="false" />
    		<!-- Maximum 10kb size. New file will be created and old file renamed -->
    		<param name="maxFileSize" value="10KB" />
    		<!-- Maximum 5 log files. Old ones will be deleted -->
    		<param name="maxBackupIndex" value="5" />
    		<!-- Location of log file -->
    		<param name="file" value="test-output/log/${logfoldername}/${logfilename}.log" />
    		<layout class="org.apache.log4j.PatternLayout">
    			<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
    		</layout>
    	</appender>
    
    
    	<root>
    	<!-- Setting Logging level  -->
    		<level value="info" />
    		<!-- Setting logging level for console -->
    		<appender-ref ref="console" />
    		<!-- Setting logging level for file -->
    		<appender-ref ref="file" />
    	</root>
    </log4j:configuration>
    
  • For advanced HTML reports, we will use Extent Reports. Right click on ‘com.testmadness.utils’ package and select New -> Class. Name the class as ‘Reports.java’. Copy the code from Advanced HTML Reports… post. However, a small update can be made on the Report location as we can refer the path already mentioned in our Constants.class.
  • Our next task is to create a ‘ExcelUtil.class’ inside ‘com.testmadness.utils’ package. This class will help us to access the test data entered in an Excel sheet. Copy the code of ExcelUtil.class’ from Data Driven Framework Development… post.
  • So far our ‘com.testmadness.utils’ package has classes for accessing property file, Log4j, Excel sheet, Constants and for generating HTML reports.
  • The final structure of ‘com.testmadness.utils’ package will look like as displayed below.

    com.testmadness.www package

 

In the next post, we will focus mainly on creating Page based objects. So stay tuned!

Part 1: Hybrid Framework Development…

So far we have covered multiple topics in Selenium Automation. And the good thing is that we are going to use most of the topics covered into the creation of our Hybrid Framework. Sounds interesting, right?

What all functionality our Hybrid Framework will contain?

  • First and foremost it will be a Maven project. We will not download individual jars as we did earlier, rather we will add dependencies in our pom.xml file.
  • And of course, it will a Selenium, TestNG project.
  • We will include like Page Object Modeling, Page Factory concepts in our framework.
  • We will add Data Driven technique in our framework for test data input.
  • The framework will have Log4j logging.
  • In addition to TestNG reports, we will also include Extent Reports for advanced HTML reports.
  • We will create user defined methods for different actions.
  • And we will also add a new topic in our Hybrid Framework and that is the use of properties file in order to store some configurable parameters of our application.

Setting up this framework will be a long and tiring affair but for sure it’s going to be an interesting one. Our demo application will be New Tours Demo, which we used in our previous posts also.

Hybrid Framework Development:

  • Our first task is to create a Maven project in Eclipse. Go to File -> New -> Project and select Maven and click Next. Use default workspace location and quick-start archetype. Enter a Group ID, in our case its ‘com.testmadness.www’, Artifact ID as ‘HybridFramework’. Click Finish to complete the project creation. Once complete, Maven will automatically create the project structure as displayed below.

    Maven Project
  • Next step is to add the dependencies in our pom.xml file. For that we will need dependencies for Selenium, TestNG, Log4j, Apache POI and Extent Reports. We can get the dependencies either by doing a search in Google or by directly going to Maven Repository website. After successful update, our pom.xml will look as below:
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    	<modelVersion>4.0.0</modelVersion>
    
    	<groupId>com.testmadness.www</groupId>
    	<artifactId>HybridFramework</artifactId>
    	<version>0.0.1-SNAPSHOT</version>
    	<packaging>jar</packaging>
    	<name>HybridFramework</name>
    	<url>http://maven.apache.org</url>
    
    	<properties>
    		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    		<maven.compiler.source>1.8</maven.compiler.source>
    		<maven.compiler.target>1.8</maven.compiler.target>
    		<selenium.version>3.4.0</selenium.version>
    		<testng.version>6.10</testng.version>
    		<log4j.version>1.2.17</log4j.version>
    		<extent.version>2.41.2</extent.version>
    		<selenium.browser>CHROME</selenium.browser>	
    <webdriver.safari.driver>/usr/bin/safaridriver</webdriver.safari.driver>
    <webdriver.firefox.driver>/Users/sejijohn/Documents/JARS/geckodriver</webdriver.firefox.driver>		<webdriver.chrome.driver>/Users/sejijohn/Documents/JARS/chromedriver 2</webdriver.chrome.driver>
    		<logfoldername>logfoldername</logfoldername>
    		<logfilename>logfilename</logfilename>
    	</properties>
    
    <build>
        <plugins>
          <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>properties-maven-plugin</artifactId>
            <version>1.0.0</version>
            <executions>
              <execution>
                <phase>generate-resources</phase>
                <goals>
                  <goal>write-project-properties</goal>
                </goals>
                <configuration>
                  <outputFile>
                    src/main/resources/system.properties
                  </outputFile>
                </configuration>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
    
    	<dependencies>
    		<dependency>
    			<groupId>org.seleniumhq.selenium</groupId>
    			<artifactId>selenium-java</artifactId>
    			<version>${selenium.version}</version>
    		</dependency>
    		<dependency>
    			<groupId>org.testng</groupId>
    			<artifactId>testng</artifactId>
    			<version>${testng.version}</version>
    		</dependency>
    		<dependency>
    			<groupId>log4j</groupId>
    			<artifactId>log4j</artifactId>
    			<version>${log4j.version}</version>
    		</dependency>
    		<dependency>
    			<groupId>com.relevantcodes</groupId>
    			<artifactId>extentreports</artifactId>
    			<version>${extent.version}</version>
    		</dependency>
                    <dependency>
    			<groupId>org.apache.poi</groupId>
    			<artifactId>poi</artifactId>
    			<version>3.16</version>
    		</dependency>
                    <dependency>
    			<groupId>org.apache.poi</groupId>
    			<artifactId>poi-ooxml</artifactId>
    			<version>3.16</version>
    		</dependency>
    	</dependencies>
    </project>
    

In the above pom.xml file, the first part (represented in pink color) has the project details like, Group ID, Artifact ID which we entered in the initial stage of our project creation. Since we selected default archetype, the packaging is in jar.

The second part (represented in blue color) is where we are setting the properties. If we want to use Java 8 language features (-source 1.8) and also want the compiled classes to be compatible with JVM 1.8 (-target 1.8), we can add the two following two properties, maven.compiler.source, maven.compiler.target with the Java version mentioned in them. The different version properties that we set, for example, selenium.version can be used to set the version of different dependencies inside pom.xml. This is not mandatory as we can directly set the versions in the dependencies. However, by doing this, we can add extra flexibility to directly update the versions from properties rather updating in the dependencies. Other properties such as selenium.browser, webdriver.safari.driver, are used to pass configurable parameters to a .properties file, which we will create shortly. Please make sure to download latest Safari, Chrome, Firefox drivers, and store in a local location. From properties we will be passing the location of different drivers to our code. The next ones are logfoldername, logfilename properties which we are using to set the location of our log files in log4j.xml.

The third part (represented in purple color) is a plugin to update the properties from pom.xml file to a .properties file inside ‘src/main/resources’ folder.

The last part (represented in red color) is where we are adding the dependencies. As mentioned earlier, we can get the dependencies and their versions by doing a Google search.

  • After updating the pom.xml file, our next step is to create a .properties file. We will use this .properties file to configure the type of browser and as well as for setting the browser properties. Always remember, that we should place the .properties file inside ‘src/main/resources’ folder and not into ‘src/main/java’ directory (keeping the same subfolder structure). For that, we need to create a source folder named resources inside ‘src/main‘ directory.
  • To create a source folder, click on Project name, select New -> Source Folder. Provide the folder name as ‘src/main/resources’.

    Source Folder creation
  • After creating resources folder, our next step is to create a .properties file. Right click on ‘src/main/resources’ folder -> New -> Other. Select File and click Next. Name the file as ‘system.properties’ and click Finish. A blank .properties file will be created inside resources folder.

    system.properties files inside resources folder
  • Now that we have updated pom.xml file and created .properties file, our next step is to update our Maven project with these changes. To update project, click on Project Name -> Maven -> Update Project.

    Update Maven project
  • After successful update, the Java System Library is updated from default 1.5 version to 1.8 version based on maven.compiler.source, maven.compiler.target properties in the pom.xml file. Also the system.properties file inside resources folder is automatically updated with all the properties from pom.xml file.

    system.properties file

With this, we have completed the initial structure of our Hybrid Framework. Our next step is to add the source codes inside our Framework. We will cover this in our next topic. Till then, Live Well and Happy Learning!