Guidelines For Automation Testing
Guidelines For Automation Testing
Steps to follow:
1) Go to Apache POI services and click on Download on the left side menu.
2) You will always get the latest version here. Click on the link for Apchae POI under Available
Downloads.
5) Select the radio button for Save File and click OK. Zip file will be saved on the system with in few
seconds.
6) Right click on the Zip file and select Extract All.
2) Click on Add External JARS and navigate to the folder where you have kept the Apache POI jar
files.
3) Select the Executable Jar files from all the folders.
Data Driven Framework with Apache POI
Excel
Most commercial automated software tools on the market support some sort of data driven testing,
which allows you to automatically run a test case multiple times with different input and validation
values. As Selenium Webdriver is more an automated testing framework than a ready-to-use tool, you
will have to put in some effort to support data driven testing in your automated tests. I usually prefer
to use Microsoft Excel as the format for storing my parameters. An additional advantage of using Excel
is that you can easily outsource the test data administration to someone other than yourself, someone
who might have better knowledge of the test cases that need to be run and the parameters required
to execute them.
How to do it
1) Download JAR files of Apache POI and Add Jars to your project library. You can download it
from here. Thats all about configuration of Apache POI with eclipse. Now you are ready to write your
test.
2) Create a New Package file and name it as testData, by right click on the Project and
select New > Package. Place all of your test data in this folder (package) whether it is a sql file,
excel file or anything.
3) Place a Excel file in the above created package location and save it asTestData.xlsx. Fill the data
in the excel like below image:
4) Add two constant variables (testData package path & Excel file name) in theConstant class.
1 package utility;
2
3 public class Constant {
4
5 public static final String URL = "http://www.store.demoqa.com";
6
7 public static final String Username = "testuser_1";
8
9 public static final String Password = "Test@123";
10
11 public static final String Path_TestData = "D://ToolsQA//OnlineStore//src//testData//"
12
13 public static final String File_TestData = "TestData.xlsx"
14
15 }
5) Create a New Class file, by right click on the utility Package and select New> Class and name
it as ExcelUtils. First we will write basic read/write methods.
1 package utility;
2
3 import java.io.FileInputStream;
4
5 import java.io.FileOutputStream;
6
7 import org.apache.poi.xssf.usermodel.XSSFCell;
8
9 import org.apache.poi.xssf.usermodel.XSSFRow;
10
11 import org.apache.poi.xssf.usermodel.XSSFSheet;
12
13 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
14
15 public class ExcelUtils {
16
17 private static XSSFSheet ExcelWSheet;
18
19 private static XSSFWorkbook ExcelWBook;
20
21 private static XSSFCell Cell;
22
23 private static XSSFRow Row;
24
25 //This method is to set the File path and to open the Excel file, Pass Excel Path and Sheetname as Arguments to this method
26
27 public static void setExcelFile(String Path,String SheetName) throws Exception {
28
29 try {
30
31 // Open the Excel file
32
33 FileInputStream ExcelFile = new FileInputStream(Path);
34
35 // Access the required test data sheet
36
37 ExcelWBook = new XSSFWorkbook(ExcelFile);
38
39 ExcelWSheet = ExcelWBook.getSheet(SheetName);
40
41 } catch (Exception e){
42
43 throw (e);
44
45 }
46
47 }
48
49 //This method is to read the test data from the Excel cell, in this we are passing parameters as Row num and Col num
50
51 public static String getCellData(int RowNum, int ColNum) throws Exception{
52
53 try{
54
55 Cell = ExcelWSheet.getRow(RowNum).getCell(ColNum);
56
57 String CellData = Cell.getStringCellValue();
58
59 return CellData;
60
61 }catch (Exception e){
62
63 return"";
64
65 }
66
67 }
68
69 //This method is to write in the Excel cell, Row num and Col num are the parameters
70
71 public static void setCellData(String Result, int RowNum, int ColNum) throws Exception {
72
73 try{
74
75 Row = ExcelWSheet.getRow(RowNum);
76
77 Cell = Row.getCell(ColNum, Row.RETURN_BLANK_AS_NULL);
78
79 if (Cell == null) {
80
81 Cell = Row.createCell(ColNum);
82
83 Cell.setCellValue(Result);
84
85 } else {
86
87 Cell.setCellValue(Result);
88
89 }
90
91 // Constant variables Test Data path and Test Data file name
92
93 FileOutputStream fileOut = new FileOutputStream(Constant.Path_TestData +
94 Constant.File_TestData);
95
96 ExcelWBook.write(fileOut);
97
98 fileOut.flush();
99
100 fileOut.close();
101
102 }catch(Exception e){
103
104 throw (e);
105
106 }
107
108 }
109
}
6) Once we are done with writing Excel functions we can go ahead and modify
the SignIn_Action module to accept the test data from excel file.
1 package appModules;
2
3 import org.openqa.selenium.WebDriver;
4
5 import pageObjects.Home_Page;
6
7 import pageObjects.LogIn_Page;
8
9 import utility.ExcelUtils;
10
11 // Now this method does not need any arguments
12
13 public class SignIn_Action {
14
15 public static void Execute(WebDriver driver) throws Exception{
16
17 //This is to get the values from Excel sheet, passing parameters (Row num & Col num)to getCellData method
18
19 String sUserName = ExcelUtils.getCellData(1, 1);
20
21 String sPassword = ExcelUtils.getCellData(1, 2);
22
23 Home_Page.lnk_MyAccount(driver).click();
24
25 LogIn_Page.txtbx_UserName(driver).sendKeys(sUserName);
26
27 LogIn_Page.txtbx_Password(driver).sendKeys(sPassword);
28
29 LogIn_Page.btn_LogIn(driver).click();
30
31 }
32
33 }
Note: In the later chapters we will see how to parameterise the row column as well, as we also have
to avoid hard coded values in the scripts. This is just to give you an idea to use Excel and we will
move forward step by step towards proper framework.
7) Create a New Class and name it as Apache_POI_TC by right click on the
automationFramework Package and select New > Class. In this we will read the values from the
Excel sheet to use them as the test data and write the test result in the Excel.
1 package automationFramework;
2
3 import java.util.concurrent.TimeUnit;
4
5 import org.openqa.selenium.WebDriver;
6
7 import org.openqa.selenium.firefox.FirefoxDriver;
8
9 import pageObjects.*;
10
11 import utility.Constant;
12
13 // Import Package utility.*
14
15 import utility.ExcelUtils;
16
17 import appModules.SignIn_Action;
18
19 public class Apache_POI_TC {
20
21 private static WebDriver driver = null;
22
23 public static void main(String[] args) throws Exception {
24
25 //This is to open the Excel file. Excel path, file name and the sheet name are parameters to this method
26
27 ExcelUtils.setExcelFile(Constant.Path_TestData + Constant.File_TestData,"Sheet1");
28
29 driver = new FirefoxDriver();
30
31 driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
32
33 driver.get(Constant.URL);
34
35 SignIn_Action.Execute(driver);
36
37 System.out.println("Login Successfully, now it is the time to Log Off buddy.");
38
39 Home_Page.lnk_LogOut(driver).click();
40
41 driver.quit();
42
43 //This is to send the PASS value to the Excel sheet in the result column.
44
45 ExcelUtils.setCellData("Pass", 1, 3);
46
47 }
48
49 }
Give it a run, see how beautify your script will execute the code.
8) Once it finished open the Excel file and check for the result.
Your Project explorer window will look like this now.
Do not worry about the red cross signs on your test scripts, it is because we have removed arguments
from SignIn_Action class.
Data Driven framework can be build up by using TestNg Data Provider.
Log4J Logging
During the running of test case user wants some information to be logged in the console. Information
could be any detail depends upon the purpose. Keeping this in mind that we are using Selenium for
testing, we need the information which helps the User to understand the test steps or any failure
during the test case execution. With the help of Log4j it is possible to enable loggings during the
Selenium test case execution for e.g. lets say you have encountered a failure in automation test script
and it has to be reported in the system. The set of information that you have required to report a bug
is :
How to do it
1) Download JAR files of Log4j and Add Jars to your project library. You can download it
from here. Thats all about configuration of Apache POI with eclipse. Now you are ready to write your
test.
2) Create a new XML file log4j.xml and place it under the Project root folder.
3) Paste the following code in the log4j.xml file.
1 package utility;
2
3 import org.apache.log4j.Logger;
4
5 public class Log {
6
7 // Initialize Log4j logs
8
9 private static Logger Log = Logger.getLogger(Log.class.getName());//
10
11 // This is to print log for the beginning of the test case, as we usually run so many test cases as a test suite
12
13 public static void startTestCase(String sTestCaseName){
14
15 Log.info("****************************************************************************************");
16
17 Log.info("****************************************************************************************");
18
19 Log.info("$$$$$$$$$$$$$$$$$$$$$ "+sTestCaseName+ " $$$$$$$$$$$$$$$$$$$$$$$$$");
20
21 Log.info("****************************************************************************************");
22
23 Log.info("****************************************************************************************");
24
25 }
26
27 //This is to print log for the ending of the test case
28
29 public static void endTestCase(String sTestCaseName){
30
31 Log.info("XXXXXXXXXXXXXXXXXXXXXXX "+"-E---N---D-"+" XXXXXXXXXXXXXXXXXXXXXX");
32
33 Log.info("X");
34
35 Log.info("X");
36
37 Log.info("X");
38
39 Log.info("X");
40
41 }
42
43 // Need to create these methods, so that they can be called
44
45 public static void info(String message) {
46
47 Log.info(message);
48
49 }
50
51 public static void warn(String message) {
52
53 Log.warn(message);
54
55 }
56
57 public static void error(String message) {
58
59 Log.error(message);
60
61 }
62
63 public static void fatal(String message) {
64
65 Log.fatal(message);
66
67 }
68
69 public static void debug(String message) {
70
71 Log.debug(message);
72
73 }
74
75 }
5) Insert log messages in Home_Page class of pageObject package.
1 package pageObjects;
2
3 import org.openqa.selenium.By;
4
5 import org.openqa.selenium.WebDriver;
6
7 import org.openqa.selenium.WebElement;
8
9 import framework.utility.Log;
10
11 public class Home_Page {
12
13 private static WebElement element = null;
14
15 public static WebElement lnk_MyAccount(WebDriver driver){
16
17 element = driver.findElement(By.id("account"));
18
19 Log.info("My Account link element found");
20
21 return element;
22
23 }
24
25 public static WebElement lnk_LogOut(WebDriver driver){
26
27 element = driver.findElement(By.id("account_logout"));
28
29 Log.info("Log Out link element found");
30
31 return element;
32
33 }
34
35 }
6) Insert log messages in LogIn_Page class of pageObject package.
1 package pageObjects;
2
3 import org.openqa.selenium.*;
4
5 import utility.Log;
6
7 public class LogIn_Page {
8
9 static WebElement element = null;
10
11 public static WebElement txtbx_UserName(WebDriver driver){
12
13 element = driver.findElement(By.id("log"));
14
15 Log.info("Username text box found");
16
17 return element;
18
19 }
20
21 public static WebElement txtbx_Password(WebDriver driver){
22
23 element = driver.findElement(By.id("pwd"));
24
25 Log.info("Password text box found");
26
27 return element;
28
29 }
30
31 public static WebElement btn_LogIn(WebDriver driver){
32
33 element = driver.findElement(By.id("login"));
34
35 Log.info("Submit button found");
36
37 return element;
38
39 }
40
41 }
7) Insert log messages in SignIn_Action class of appModule package.
1 package appModules;
2
3 import org.openqa.selenium.WebDriver;
4
5 import pageObjects.Home_Page;
6
7 import pageObjects.LogIn_Page;
8
9 import utility.ExcelUtils;
10
11 import utility.Log;
12
13 public class SignIn_Action {
14
15 public static void Execute(WebDriver driver) throws Exception{
16
17 String sUserName = ExcelUtils.getCellData(1, 1);
18
19 Log.info("Username picked from Excel is "+ sUserName );
20
21 String sPassword = ExcelUtils.getCellData(1, 2);
22
23 Log.info("Password picked from Excel is "+ sPassword );
24
25 Home_Page.lnk_MyAccount(driver).click();
26
27 Log.info("Click action performed on My Account link");
28
29 LogIn_Page.txtbx_UserName(driver).sendKeys(sUserName);
30
31 Log.info("Username entered in the Username text box");
32
33 LogIn_Page.txtbx_Password(driver).sendKeys(sPassword);
34
35 Log.info("Password entered in the Password text box");
36
37 LogIn_Page.btn_LogIn(driver).click();
38
39 Log.info("Click action performed on Submit button");
40
41 }
42
43 }
8) Now it is the time to insert log message in to your test script but before that create a New Class
and name it as Log4j_Logging_TC by right click on the automationFramework Package and
select New > Class.
1 package automationFramework;
2
3 // Import Package Log4j.*
4
5 import org.apache.log4j.xml.DOMConfigurator;
6
7 import java.util.concurrent.TimeUnit;
8
9 import org.openqa.selenium.*;
10
11 import pageObjects.*;
12
13 import utility.*;
14
15 import appModules.*;
16
17 public class Log4j_Logging_TC {
18
19 private static WebDriver driver = null;
20
21 public static void main(String[] args) throws Exception {
22
23 // Provide Log4j configuration settings
24
25 DOMConfigurator.configure("log4j.xml");
26
27 Log.startTestCase("Selenium_Test_001");
28
29 ExcelUtils.setExcelFile(Constant.Path_TestData + Constant.File_TestData,"Sheet1");
30
31 Log.info(" Excel sheet opened");
32
33 driver = new FirefoxDriver();
34
35 Log.info("New driver instantiated");
36
37 driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
38
39 Log.info("Implicit wait applied on the driver for 10 seconds");
40
41 driver.get(Constant.URL);
42
43 Log.info("Web application launched");
44
45 SignIn_Action.Execute(driver);
46
47 System.out.println("Login Successfully, now it is the time to Log Off buddy.");
48
49 Home_Page.lnk_LogOut(driver).click();
50
51 Log.info("Click action is perfomred on Log Out link");
52
53 driver.quit();
54
55 Log.info("Browser closed");
56
57 ExcelUtils.setCellData("Pass", 1, 3);
58
59 Log.endTestCase("Selenium_Test_001");
60
61 }
62
63 }
Once your test is complete, go to your project root folder and open the log file. Your log file will look
like this:
TestNG Parameters
Everybody knows the importance of Parameterization in testing and in automation testing. It allows
us to automatically run a test case multiple times with different input and validation values. As
Selenium Webdriver is more an automated testing framework than a ready-to-use tool, you will have
to put in some effort to support data driven testing in your automated tests. I usually prefer to use
Microsoft Excel as the format for storing my parameters but so many of my followers have requested
to write an article on TestNG Data Provider.
TestNG again gives us another interesting feature called TestNG Parameters. TestNG lets you pass
parameters directly to your test methods with your testng.xml.
How to do it
Let me take a very simple example of LogIn application, where the username and password is
required to clear the authentication.
1) Create a test on my demo OnlineStore application to perform LogIn which takes the two string
argument as username & password.
2) Provide Username & Password as parameter using TestNG Annotation.
1 package automationFramework;
2
3 import java.util.concurrent.TimeUnit;
4
5 import org.openqa.selenium.By;
6
7 import org.openqa.selenium.WebDriver;
8
9 import org.openqa.selenium.firefox.FirefoxDriver;
10
11 import org.testng.annotations.Test;
12
13 import org.testng.annotations.Parameters;
14
15 public class TestngParameters {
16
17 private static WebDriver driver;
18
19 @Test
20
21 @Parameters({ "sUsername", "sPassword" })
22
23 public void test(String sUsername, String sPassword) {
24
25 driver = new FirefoxDriver();
26
27 driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
28
29 driver.get("http://www.store.demoqa.com");
30
31 driver.findElement(By.xpath(".//*[@id='account']/a")).click();
32
33 driver.findElement(By.id("log")).sendKeys(sUsername);
34
35 driver.findElement(By.id("pwd")).sendKeys(sPassword);
36
37 driver.findElement(By.id("login")).click();
38
39 driver.findElement(By.xpath(".//*[@id='account_logout']/a")).click();
40
41 driver.quit();
42
43 }
44
45 }
3) The parameter would be passed values from testng.xml which we will see in the next step.
1 <suite name="Suite">
2
3 <test name="ToolsQA">
4
5 <parameter name="sUsername" value="testuser_1"/>
6
7 <parameter name="sPassword" value="Test@123"/>
8
9 <classes>
10
11 <class name="automationFramework.TestngParameters" />
12
13 </classes>
14
15 </test>
16
17 </suite>
Now, run the testng.xml, which will run the parameterTest method. TestNG will try to find a
parameter named sUsername & sPassword.
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 same Sign In examples using Dataproviders.
How to do it
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 test() 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:
1 package automationFramework;
2
3 import java.util.concurrent.TimeUnit;
4
5 import org.openqa.selenium.By;
6
7 import org.openqa.selenium.WebDriver;
8
9 import org.openqa.selenium.firefox.FirefoxDriver;
10
11 import org.testng.annotations.DataProvider;
12
13 import org.testng.annotations.Test;
14
15 public class DataProviderTest {
16
17 private static WebDriver driver;
18
19 @DataProvider(name = "Authentication")
20
21 public static Object[][] credentials() {
22
23 return new Object[][] { { "testuser_1", "Test@123" }, { "testuser_1", "Test@123" }};
24
25 }
26
27 // Here we are calling the Data Provider object with its Name
28
29 @Test(dataProvider = "Authentication")
30
31 public void test(String sUsername, String sPassword) {
32
33 driver = new FirefoxDriver();
34
35 driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
36
37 driver.get("http://www.store.demoqa.com");
38
39 driver.findElement(By.xpath(".//*[@id='account']/a")).click();
40
41 driver.findElement(By.id("log")).sendKeys(sUsername);
42
43 driver.findElement(By.id("pwd")).sendKeys(sPassword);
44
45 driver.findElement(By.id("login")).click();
46
47 driver.findElement(By.xpath(".//*[@id='account_logout']/a")).click();
48
49 driver.quit();
50
51 }
52
53 }
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, once it is finished the results will look like this in the TestNg
Result window.
Note: As the test data is provided two times, the above test executed two times completely.
Why Framework
The testing framework should offer point-and-click interface for accessing and
interacting with the application components under testas 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.
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 screen
shots 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.
Test engineers are encapsulated from the complexities and critical aspects of the
code. Engineers are exposed only to the implemented libraries and tests are executed by just invoking
the libraries.
How to do it
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 Home Page and LogIn Page.
3. Now create a Static Method for each Element (Object) in the Home Page. Each method will have
an Argument (driver) and a Return value (element).
1 package pageObjects;
2
3 import org.openqa.selenium.By;
4
5 import org.openqa.selenium.WebDriver;
6
7 import org.openqa.selenium.WebElement;
8
9 public class Home_Page {
10
11 private static WebElement element = null;
12
13 public static WebElement lnk_MyAccount(WebDriver driver){
14
15 element = driver.findElement(By.id("account"));
16
17 return element;
18
19 }
20
21 public static WebElement lnk_LogOut(WebDriver driver){
22
23 element = driver.findElement(By.id("account_logout"));
24
25 return element;
26
27 }
28
29 }
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 LogIn Page class.
1 package pageObjects;
2
3 import org.openqa.selenium.*;
4
5 import org.openqa.selenium.WebDriver;
6
7 import org.openqa.selenium.WebElement;
8
9 public class LogIn_Page {
10
11 private static WebElement element = null;
12
13 public static WebElement txtbx_UserName(WebDriver driver){
14
15 element = driver.findElement(By.id("log"));
16
17 return element;
18
19 }
20
21 public static WebElement txtbx_Password(WebDriver driver){
22
23 element = driver.findElement(By.id("pwd"));
24
25 return element;
26
27 }
28
29 public static WebElement btn_LogIn(WebDriver driver){
30
31 element = driver.findElement(By.id("login"));
32
33 return element;
34
35 }
36
37 }
4) Create a New Class and name it as POM_TC by right click on the automationFramework
Package and select New > Class. We will be creating all our test cases under this package.
Now convert your old First Test Case in to the new Page Object Model test case.
1 package automationFramework;
2
3 import java.util.concurrent.TimeUnit;
4
5 import org.openqa.selenium.WebDriver;
6
7 import org.openqa.selenium.firefox.FirefoxDriver;
8
9 // Import package pageObject.*
10
11 import pageObjects.Home_Page;
12
13 import pageObjects.LogIn_Page;
14
15 public class PageObjectModel {
16
17 private static WebDriver driver = null;
18
19 public static void main(String[] args) {
20
21 driver = new FirefoxDriver();
22
23 driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
24
25 driver.get("http://www.store.demoqa.com");
26
27 // Use page Object library now
28
29 Home_Page.lnk_MyAccount(driver).click();
30
31 LogIn_Page.txtbx_UserName(driver).sendKeys("testuser_1");
32
33 LogIn_Page.txtbx_Password(driver).sendKeys("Test@123");
34
35 LogIn_Page.btn_LogIn(driver).click();
36
37 System.out.println(" Login Successfully, now it is the time to Log Off buddy.")
38
39 Home_Page.lnk_LogOut(driver).click();
40
41 driver.quit();
42
43 }
44
45 }
You will notice that once you type Home_Page in your test script and the moment you press dot, all
the methods in the Home Page will display. 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.
Your Project explorer window will look like this now.
It is advisable to maintain Page Objects Repository in the same way QTP maintain its Repository.
Please visit Selenium Object Repository section to learn more.
How to do it..
Look for repeated functionality in your application for example the login functionality. We can simple
wrap this functionality in a method and we can give it a sensible name.
1) Create a New Package file and name it as appModule, 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 New Class and name it as SignIn_Action by right click on package appModule and
select New > Class. It will add new class SignIn_Action under package appModule.
3) Now create a Public Static Void Method and name it as Execute and club the following steps in
to it:
Click on the My Account link.
Enter Username
Enter Password
Click on the Submit button
This method will not have any Argument (driver) and Return value as it is a void method.
1 package framework.appModule;
2
3 import org.openqa.selenium.WebDriver;
4
5 import framework.pageObject.Home_Page;
6
7 import framework.pageObject.LogIn_Page;
8
9 public class SignIn_Action{
10
11 public static void Execute(WebDriver driver){
12
13 Home_Page.lnk_SignIn(driver).click();
14
15 LogIn_Page.txtbx_UserName(driver).sendKeys("testuser_1");
16
17 LogIn_Page.txtbx_Password(driver).sendKeys("Test@123");
18
19 LogIn_Page.btn_LogIn(driver).click();
20
21 }
22
23 }
Note: Please visit First Test Case & Page Object Model first, in case you are finding it hard to
understand the above used SignIn_Action class.
4) Create a New Class and name it as Module_TC by right click on the automationFramework
Package and select New > Class. We will be creating all our test cases under this package.
Now convert your old POM_TC in to the new Module based test case.
1 package automationFramework;
2
3 import java.util.concurrent.TimeUnit;
4
5 import org.openqa.selenium.WebDriver;
6
7 import org.openqa.selenium.firefox.FirefoxDriver;
8
9 // Import package appModule.*
10
11 import appModules.SignIn_Action;
12
13 import pageObjects.Home_Page;
14
15 public class Module_TC {
16
17 private static WebDriver driver = null;
18
19 public static void main(String[] args) {
20
21 driver = new FirefoxDriver();
22
23 driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
24
25 driver.get("http://www.store.demoqa.com");
26
27 // Use your Module SignIn now
28
29 SignIn_Action.Execute(driver);
30
31 System.out.println("Login Successfully, now it is the time to Log Off buddy.");
32
33 Home_Page.lnk_LogOut(driver).click();
34
35 driver.quit();
36
37 }
38
39 }
You will notice that your call to SignIn_Action will automatically execute all the steps mentioned under
it.
Your Project explorer window will look like this now.
Function Parameters
It is always a good practice to pass parameters when calling the method, rather than providing
parameters inside the method. We can pass parameters through methods, just as in normal
programming code. The code below will show us how we can login with parameterized username and
password.
How to do it
1) First lets have a look over our previous example of SignIn_Action class.
1 package framework.appModule;
2
3 import org.openqa.selenium.WebDriver;
4
5 import framework.pageObject.Home_Page;
6
7 import framework.pageObject.LogIn_Page;
8
9 public class SignIn_Action{
10
11 public static void Execute(WebDriver driver){
12
13 Home_Page.lnk_SignIn(driver).click();
14
15 LogIn_Page.txtbx_UserName(driver).sendKeys("testuser_1");
16
17 LogIn_Page.txtbx_Password(driver).sendKeys("Test@123");
18
19 LogIn_Page.btn_LogIn(driver).click();
20
21 }
22
23 }
Note: Please visit First Test Case, Page Object Model & Modularity first, in case you are finding it
hard to understand the above used SignIn_Action class.
2) Modify the above Execute method of class SignIn_Action to accept string Arguments (Username &
Password).
1 package appModules;
2
3 import org.openqa.selenium.WebDriver;
4
5 import pageObjects.Home_Page;
6
7 import pageObjects.LogIn_Page;
8
9 public class SignIn_Action {
10
11 // Pass Arguments (Username and Password) as string
12
13 public static void Execute(WebDriver driver,String sUsername, String sPassword){
14
15 Home_Page.lnk_MyAccount(driver).click();
16
17 // Enter sUsername variable in place of hardcoded value
18
19 LogIn_Page.txtbx_UserName(driver).sendKeys(sUsername);
20
21 // Enter sPassword variable in place of hardcoded value
22
23 LogIn_Page.txtbx_Password(driver).sendKeys(sPassword);
24
25 LogIn_Page.btn_LogIn(driver).click();
26
27 }
28
29 }
3) Create a New Class and name it as Param_TC by right click on the automationFramework
Package and select New > Class. We will be creating all our test cases under this package.
Now convert your old Module_TCin to the new passing parameters based test case.
1 package automationFramework;
2
3 import java.util.concurrent.TimeUnit;
4
5 import org.openqa.selenium.WebDriver;
6
7 import org.openqa.selenium.firefox.FirefoxDriver;
8
9 import appModules.SignIn_Action;
10
11 import pageObjects.Home_Page;
12
13 public class Param_TC {
14
15 private static WebDriver driver = null;
16
17 public static void main(String[] args) {
18
19 driver = new FirefoxDriver();
20
21 driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
22
23 driver.get("http://www.store.demoqa.com");
24
25 // Pass the Arguments (Username and Password) to this method
26
27 SignIn_Action.Execute(driver, "testuser_1","Test@123");
28
29 System.out.println("Login Successfully, now it is the time to Log Off buddy.");
30
31 Home_Page.lnk_LogOut(driver).click();
32
33 driver.quit();
34
35 }
36
37 }
You see how easy it is to pass arguments to your methods. It increase you code readability.
Now your Project explorer window will look like this:
Note: But it is still not the best idea to hardcode your input anywhere in your test script, as it will still
impact the bulk of your test scripts if there is any change in user data. I used this example just to give
you an idea to how we use arguments in method.
In the next chapter of Constant Variable we will learn how to avoid hardcode values in our code.
tant Variables
Test data can be of two types, fixed or variable. If it is fixed, we can easily hard code the test data in
to our test scripts. But sometimes the fixed test data is also used in so many scripts and if it gets
changed then it is a huge task to update all the effected test scripts for example the URL of your test
application. It remains same but once you shifted to other environment, you need to change it in all of
your test scripts. We can easily place the URL in Text file or Excel file outside our test scripts but Java
gives us special feature of creating Constants variables which works exactly the same as Environment
and Global variable in QTP.
How to do it
1) Create a New Package file and name it as utility, by right click on the Project and
select New > Package.
2) Create a New Class file, by right click on the above created Package and select New > Class and
name it as Constant.
3) Assign keywords in this class to your fixed data for e.g. Url, Username and Password.
1 package utility;
2
3 public class Constant {
4
5 public static final String URL = "http://www.store.demoqa.com";
6
7 public static final String Username = "testuser_1";
8
9 public static final String Password = "Test@123";
10
11 }
Constants Variables are declared as public static, so that they can be called in any other methods
without instantiate the class.
Constant Variables are declared a final, so that they cannot be changed during the execution.
4) SignIn_Class will remain same.
1 package appModules;
2
3 import org.openqa.selenium.WebDriver;
4
5 import pageObjects.Home_Page;
6
7 import pageObjects.LogIn_Page;
8
9 public class SignIn_Action {
10
11 public static void Execute(WebDriver driver,String sUsername, String sPassword){
12
13 Home_Page.lnk_MyAccount(driver).click();
14
15 LogIn_Page.txtbx_UserName(driver).sendKeys(sUsername);
16
17 LogIn_Page.txtbx_Password(driver).sendKeys(sPassword);
18
19 LogIn_Page.btn_LogIn(driver).click();
20
21 }
22
23 }
Note: Please visit First Test Case, Page Object Model, Modular Driven &Function
Parameters first, in case you are finding it hard to understand the above used SignIn_Action class.
5) Create a New Class and name it as Global_Var_TC by right click on the
automationFramework Package and select New > Class. We will be creating all our test cases
under this package.
Now pass your Constant Variables (URL, Username and Password) as arguments to
your Execute method of SignIn_Action class in your Global_Var_TC test case.
1 package automationFramework;
2
3 import java.util.concurrent.TimeUnit;
4
5 import org.openqa.selenium.WebDriver;
6
7 import org.openqa.selenium.firefox.FirefoxDriver;
8
9 import pageObjects.Home_Page;
10
11 import appModules.SignIn_Action;
12
13 // Import package utility.*
14
15 import utility.Constant;
16
17 public class Global_Var_TC {
18
19 private static WebDriver driver = null;
20
21 public static void main(String[] args) {
22
23 driver = new FirefoxDriver();
24
25 driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
26
27 // Launch the Online Store Website using Constant Variable
28
29 driver.get(Constant.URL);
30
31 // Pass Constant Variables as arguments to Execute method
32
33 SignIn_Action.Execute(driver,Constant.Username,Constant.Password);
34
35 System.out.println("Login Successfully, now it is the time to Log Off buddy.");
36
37 Home_Page.lnk_LogOut(driver).click();
38
39 driver.quit();
40
41 }
42
43 }
You will notice that once you type Constant and the moment you press dot, all the variables in the
Constant class will display. We can expose variables in order to reduce duplicated code. We are able to
call these Constant variables multiple times. This will ensure a better maintainable test code, because
we only have to make adjustments and improvements in one particular place.
Your Project explorer window will look like this now.
When the test data is not fixed or if the same test script can be executed with the large amount of test
data, we use external files for test data. In next chapter of Data Driven Technique Apache
POI you will see how to set large amount of variable test data for the test scripts.
User Defined Functions
User defined functions (UDF) are the functions which are created by users as per their own
requirement. In order to use a UDF, it is necessary to call the appropriate package file at the
beginning of the program. The header file informs the program of the name, type, and number and
type of arguments, of all of the functions contained.
1 import<packageName>
An UDF function is accessed by simply writing the function name, followed by a list of arguments,
which represent the information being passed to the function. The arguments must be enclosed in
parentheses, and separated by commas: they can be constants, variables, or more complex
expressions.
Automation Best Practices: Avoid logics when writing automation test scripts. Every logic is to be
maintained in the function libraries and only be called with their name in the test scripts. Every
arthematic calculation, date calculation, string manipulation etc. should be avoided in the Test scripts
rather put them in to the functions and use them.
Benefits of User Defined Functions
Can be used in a number of places without rewriting the code.
Code can be made less complex and easier to write.
Parameters can be passed to the function.
Simpler to invoke.
For example: It is a three steps process to open a URL. First Instantiate a New driver,
second Apply an Implicit wait on the driver and third Navigate to URL. Browser can be any
browser; it can be Mozilla, IE or any. It makes sense to create a function for opening a browser which
will accept an argument (Browser Type) and it will open that particular browser. This Browser Type
argument will be driven from the Test Data sheet. To achieve this few more functions are required.
1. Function One: openBrowser(int iTestCaseRow), it will return a WebDriver
2. Function Two: getTestCaseName(String sTestCase), it will return refined Test case name
3. Function Three: getRowContains(String sTestCaseName, int colNum), it will return the row
number of the Test case name from the test data sheet.
How to use it
1) Create a new column (Browser) in the Test Data sheet.
Make some entries in the Constant class for the column numbers:
1 package utility;
2
3 public class Constant {
4
5 public static final String URL = "http://www.store.demoqa.com";
6
7 public static final String Path_TestData = "D://ToolsQA//OnlineStore//src//testData//";
8
9 public static final String File_TestData = "TestData.xlsx";
10
11 //Test Data Sheet Columns
12
13 public static final int Col_TestCaseName = 0;
14
15 public static final int Col_UserName =1 ;
16
17 public static final int Col_Password = 2;
18
19 public static final int Col_Browser = 3;
20
21 }
2) Create a New Class by right click on the utility package then select New > Class and name it
as Utils. Now create a Static Method for Initiate Browser in the Utils class. This method will have
an Argument (TestCase Row) and a Return value (WebDriver).
1 public class Utils {
2
3 public static WebDriver driver = null;
4
5 public static WebDriver openBrowser(int iTestCaseRow) throws Exception{
6
7 String sBrowserName;
8
9 try{
10
11 sBrowserName = ExcelUtils.getCellData(iTestCaseRow, Constant.Col_Browser);
12
13 if(sBrowserName.equals("Mozilla")){
14
15 driver = new FirefoxDriver();
16
17 Log.info("New driver instantiated");
18
19 driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
20
21 Log.info("Implicit wait applied on the driver for 10 seconds");
22
23 driver.get(Constant.URL);
24
25 Log.info("Web application launched successfully");
26
27 }
28
29 }catch (Exception e){
30
31 Log.error("Class Utils | Method OpenBrowser | Exception desc : "+e.getMessage());
32
33 }
34
35 return driver;
36
37 }
38
39 }
3) To get the Test Case row from the Test data sheet, it is required to get Test Case name, so
that it can be searched in the Test Data sheet. Write a function in Utils class to get the Test Case
name. Test case name can be easily get by using this.toString(). This function will return the
package name and the class name for e.g. automationFramework.UDF_TC@2550036c. Another
function is required to refine the long test case name in to UDF_TC.
4) Once Test Case name is captured, it can be used as an Argument for a function which will return
the Test case row from the Excel sheet.
1 package automationFramework;
2
3 import org.apache.log4j.xml.DOMConfigurator;
4
5 import org.openqa.selenium.WebDriver;
6
7 import org.testng.annotations.*;
8
9 import pageObjects.*;
10
11 import utility.*;
12
13 import appModules.*;
14
15 public class UDF_TC {
16
17 public WebDriver driver;
18
19 private String sTestCaseName;
20
21 private int iTestCaseRow;
22
23 @BeforeMethod
24
25 public void beforeMethod() throws Exception {
26
27 DOMConfigurator.configure("log4j.xml");
28
29 sTestCaseName = this.toString();
30
31 sTestCaseName = Utils.getTestCaseName(this.toString());
32
33 Log.startTestCase(sTestCaseName);
34
35 ExcelUtils.setExcelFile(Constant.Path_TestData + Constant.File_TestData,"Sheet1");
36
37 iTestCaseRow = ExcelUtils.getRowContains(sTestCaseName,Constant.Col_TestCaseName);
38
39 driver = Utils.openBrowser(iTestCaseRow);
40
41 }
42
43 @Test
44
45 public void main() throws Exception {
46
47 SignIn_Action.Execute(driver);
48
49 System.out.println("Login Successfully, now it is the time to Log Off buddy.");
50
51 Home_Page.lnk_LogOut(driver).click();
52
53 Log.info("Click action is performed on Log Out link");
54
55 }
56
57 @AfterMethod
58
59 public void afterMethod() {
60
61 driver.quit();
62
63 }
64
65 }
Isnt it easy to call functions rather than writing them again and again and increase code complexity.
What if I give you an approach which gives you the same behavior we have in QTP. Once you type the
page name, it will give you different parent elements only and on selecting parent element, it will give
you linked child elements only.
How to do it
1) Create a New Class by right click on the pageObjects package then select New > Class and
name it as ProductListing_Page.
1 package pageObjects;
2
3 import org.openqa.selenium.WebDriver;
4
5 import org.openqa.selenium.WebElement;
6
7 public class ProductListing_Page {
8
9 public static class Product_1{
10
11 public static WebElement txt_Price(WebDriver driver){
12
13 WebElement element = null;
14
15 // Write Code to find element here
16
17 return element;
18
19 }
20
21 public static WebElement txt_SalesPrice(WebDriver driver){
22
23 WebElement element = null;
24
25 // Write Code to find element here
26
27 return element;
28
29 }
30
31 public static WebElement img_Product(WebDriver driver){
32
33 WebElement element = null;
34
35 // Write Code to find element here
36
37 return element;
38
39 }
40
41 public static WebElement txt_Name(WebDriver driver){
42
43 WebElement element = null;
44
45 // Write Code to find element here
46
47 return element;
48
49 }
50
51 public static WebElement txt_Desc(WebDriver driver){
52
53 WebElement element = null;
54
55 // Write Code to find element here
56
57 return element;
58
59 }
60
61 public static WebElement btn_AddToCart( WebDriver driver){
62
63 WebElement element = null;
64
65 // Write Code to find element here
66
67 return element;
68
69 }
70
71 }
72
73 }
You are done with creating Intellisence structure for your Selenium Object Repository. Now lets taste
the benefits of it.
4) Just type ProductListing_Page in your test script and press dot. It will display all the products you
have specified in your
class.
5) Select Product_1 and again press dot, it will now display all the child elements associated with the
parent Product_1.
Now your complete command will look exactly like QTP command.
1 ProductListing_Page.Product_1.btn_AddToCart(driver).click();
Tell me now, isnt it amazing?
One more example of dividing page in to different groups. Look at the screen of a Shopping website.
We can easily divide this heavy loaded Home Page in to three different sections like Header, Center
Content and Footer. Out of which Header and Footer will remain same through out the website and
can be called again and again through Home Page only.
Before jumping on the main topic of Exception Handling in Selenium Automation Framework,
it is better to have basic understanding of Error, Exception, Exception Handling, Try, Catch, Throw and
Throws statement.
What is an Exception
An Exception is an event, which occurs during the execution of a program, that disrupts the normal
flow of the programs instructions or in simple words, any issue which makes your test case stop in
between the execution is an Exception.
1 try
2
3 {
4
5 // Some code
6
7 }catch(Exception e){
8
9 // Code for Handling the exception
10
11 }
Multiple Catch blocks: A try block can be followed by multiple catch blocks. Like I said earlier, that
there are multiple exceptions and you can expect more than one type of exception on a single code
block and if you like to handle each type of exception separately with a separate block of code. The
syntax for multiple catch blocks looks like the following:
1 try
2
3 {
4
5 //Some code
6
7 }catch(ExceptionType1 e1){
8
9 //Code for Handling the Exception 1
10
11 }catch(ExceptionType2 e2){
12
13 //Code for Handling the Exception 2
14
15 }
There is no restriction on the number of the catch blocks, you can use more than two. You may be
wondering that how does it work. It is pretty simple, if an exception occurs in the protected code, the
exception is thrown to the first catch block in the list. If the exception thrown matches the
ExceptionType1, it gets caught there and it executes the code which is under the same exception
block. If not, the exception passes down to the second catch statement and goes on like this.
Note: In case the exception does not match with any exception type and falls through all catches, the
current method stops execution and exception is thrown. That is why it is advisable to include default
exception as well in the end, so in case if the exception falls through, it can be handled by the default
one.
Throw: Sometimes we want to generate exception explicitly in our code, for example in Selenium
Automation Framework most of the time we print self-written logs, once we catch an exception and
then we need to throw that exception back to the system so that the test case can be
terminated. Throw keyword is used to throw exception to the runtime to handle it.
Throws: When we are throwing any exception in a method and not handling it, then we need to
use throws keyword in method signature to let caller program know the exceptions that might be
thrown by the method.
1 // Method Signatur\
2
3 public static void anyFunction() throws Exception{
4
5 try{
6
7 // write your code here
8
9 }catch (Exception e){
10
11 // Do whatever you wish to do here
12
13 // Now throw the exception back to the system
14
15 throw(e);
16
17 }
18
19 }
Multiple Exceptions: We can provide multiple exceptions in the throws clause.
1 try
2
3 {
4
5 //Protected code
6
7 }catch(ExceptionType1 e1)
8
9 {
10
11 //Catch block
12
13 }catch(ExceptionType2 e2)
14
15 {
16
17 //Catch block
18
19 }catch(ExceptionType3 e3)
20
21 {
22
23 //Catch block
24
25 }finally
26
27 {
28
29 //The finally block always executes.
30
31 }
1 try{
2
3 myTestDriver.findElement(By.xpath("//*[@id='register']")).click();
4
5 }catch (TimeoutException toe) {
6
7 wait.until( ExpectedConditions.elementToBeClickable(By.xpath("//*[@id='register']")));
8
9 myTestDriver.findElement(By.xpath("//*[@id='register']")).click();
10
11 }catch (Exception e) {
12
13 Log.error("Register element is not found.");
14
15 throw(e);
16
17 }
18
19 }
Example 3: Lets assume that in Selenium WebDriver you want to verify the presence of any element
on the page. You would not be able to get this with element locator because if the element is present,
your locator will work and you will easily be able to print that the element is present but in case your
element is not present on the page, your locator will fail and simply throw the exception. This case
would be easily handled with the self-written function.
What is an Exception
An Exception is an event, which occurs during the execution of a program, that disrupts the normal
flow of the programs instructions or in simple words, any issue which makes your test case stop in
between the execution is an Exception.
1 try
2
3 {
4
5 // Some code
6
7 }catch(Exception e){
8
9 // Code for Handling the exception
10
11 }
Multiple Catch blocks: A try block can be followed by multiple catch blocks. Like I said earlier, that
there are multiple exceptions and you can expect more than one type of exception on a single code
block and if you like to handle each type of exception separately with a separate block of code. The
syntax for multiple catch blocks looks like the following:
1 try
2
3 {
4
5 //Some code
6
7 }catch(ExceptionType1 e1){
8
9 //Code for Handling the Exception 1
10
11 }catch(ExceptionType2 e2){
12
13 //Code for Handling the Exception 2
14
15 }
There is no restriction on the number of the catch blocks, you can use more than two. You may be
wondering that how does it work. It is pretty simple, if an exception occurs in the protected code, the
exception is thrown to the first catch block in the list. If the exception thrown matches the
ExceptionType1, it gets caught there and it executes the code which is under the same exception
block. If not, the exception passes down to the second catch statement and goes on like this.
Note: In case the exception does not match with any exception type and falls through all catches, the
current method stops execution and exception is thrown. That is why it is advisable to include default
exception as well in the end, so in case if the exception falls through, it can be handled by the default
one.
Throw: Sometimes we want to generate exception explicitly in our code, for example in Selenium
Automation Framework most of the time we print self-written logs, once we catch an exception and
then we need to throw that exception back to the system so that the test case can be
terminated. Throw keyword is used to throw exception to the runtime to handle it.
Throws: When we are throwing any exception in a method and not handling it, then we need to
use throws keyword in method signature to let caller program know the exceptions that might be
thrown by the method.
1 // Method Signatur\
2
3 public static void anyFunction() throws Exception{
4
5 try{
6
7 // write your code here
8
9 }catch (Exception e){
10
11 // Do whatever you wish to do here
12
13 // Now throw the exception back to the system
14
15 throw(e);
16
17 }
18
19 }
Multiple Exceptions: We can provide multiple exceptions in the throws clause.
1 try
2
3 {
4
5 //Protected code
6
7 }catch(ExceptionType1 e1)
8
9 {
10
11 //Catch block
12
13 }catch(ExceptionType2 e2)
14
15 {
16
17 //Catch block
18
19 }catch(ExceptionType3 e3)
20
21 {
22
23 //Catch block
24
25 }finally
26
27 {
28
29 //The finally block always executes.
30
31 }
1 try{
2
3 myTestDriver.findElement(By.xpath("//*[@id='register']")).click();
4
5 }catch (TimeoutException toe) {
6
7 wait.until( ExpectedConditions.elementToBeClickable(By.xpath("//*[@id='register']")));
8
9 myTestDriver.findElement(By.xpath("//*[@id='register']")).click();
10
11 }catch (Exception e) {
12
13 Log.error("Register element is not found.");
14
15 throw(e);
16
17 }
18
19 }
Example 3: Lets assume that in Selenium WebDriver you want to verify the presence of any element
on the page. You would not be able to get this with element locator because if the element is present,
your locator will work and you will easily be able to print that the element is present but in case your
element is not present on the page, your locator will fail and simply throw the exception. This case
would be easily handled with the self-written function.
The above categorization can be done and maintained with the help of Excel spread sheet:
Test Step: It is a very small description of the Test Step or the description of the Action going to
perform on Test Object.
Test Object: It is the name of the Web Page object/element, like Username & Password.
Action: It is the name of the action, which is going to perform on any Object such
as click, open browser, input etc.
Test Data: Data can be any value which is needed by the Object to perform any action, like
Username value for Username field.
The idea behind the Keyword Driven approach in automation is to separate the coding from the test
case & test step. This helps a non technical person to understand the automation very well. With this a
manual tester can write Automation scripts. This does not mean that an automation tester is not
needed but in any Keyword Driven project, a hard core technical coder is must needed for setting up
the framework and to work on regular changes and updates of background automation code. But for
an example an automation team can have two manual tester and a automation coder.
Let just understand this concept with the help of an example of our Demo Online Store Application.
Consider that you have to automate a flow where you would need to do the following things:
1. Open a Browser
2. Navigate to URL
3. Click on My Account button
4. Enter Username
5. Enter Password
6. Click on LogIn button
7. Click on LogOut button
8. Close the Browser
Below is the list of common components that you would required to achieve the task:
1. Excel Sheet: This is the sheet which keeps most of the data for Keyword Driven which is needed
for the test like Test Case, Test Steps, Test Objects and Actions.
2. Object Repository: Property file to store the html elements properties of the web application, this
property file will be linked with the Objects in the test
3. Keyword Function Library: In keyword Driven Framework function file plays an important role,
as it stores the working of the actions, so that each action can be callable from this file
4. Data Sheet: Excel file to store the Data value needed by the object to perform some action on it
5. Execution Engine: Test is the only test script we have in Keyword Framework and it contains all
the code to drive the test from Excel sheet, Function Lib and Properties file.
The below image shows the generic work-flow of Keyword Driven Framework:
From the above figure, you can see that the generic flow of a Keyword Driven Framework is something
like this
Execution Engine starts the test and connect with the bundle of test cases and start executing
one by one
Once Test Case is picked, linked test steps are followed sequentially
Test Steps are further connected with Page Objects, Actions & Test Data
Once Execution Engine gets all the required info to perform a test step, it connects with application
and do the step.
Advantages:
1. Less Technical Expertise: Once Framework is set up, manual testers or non technical testers can
easily write test scripts for automation.
2. Easy To Understand: As it is maintained in Excel sheet and no coding is exposed, the test scripts
are easy to read and understand. Keywords & actions resemble so closely manual test cases, which
become easier to write and maintain.
3. Early Start: You can start building Keyword Driven test cases before the application is delivered,
as Object Repository can be easily set up at the later stage. Using information gathered from
Requirements or other documentation, keyword data tables can be created that mirror
corresponding manual test procedures.
4. Re-usability of component: With implementing modularization in Keyword Driven, Re-usability
can be further increased.
5. Re-usability of code: As there is just one Execution Engine in Keyword Driven Framework, it
encourage extreme code re-usability.
Enough talk about it lets get started.
In this tutorial we will learn how to set up Hybrid Keyword Driven Framework. I called it with the
prefix Hybrid because, Originally it is Just a Keyword Driven Framework but when we implement Data
Driven technique in it, it can be called Hybrid Keyword Framework.
Prerequisite:
1. Java is installed on your computer, to learn more visit Set Up Java.
2. Eclipse IDE should be installed, to learn more visit Set Up Eclipse.
3. WebDriver client is installed on your machine, to learn more visit Set Up WebDriver Java Client.
4. Eclipse IDE is configured with Selenium WebDriver on your machine, to learn more visit Configure
Eclipse with WebDriver.
Now lets write a simple test case of LogIn & LogOut which we discussed on previous chapter. I could
have taken the complete end to end flow, but it will increase the size of the chapters a lot.
How to do it
1. Create a New Package file and name it as executionEngine, by right click on the Project and
select New > Package. We will be creating different packages for Utilities & Configuration files. 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 name it as DriverScript, by right click on the above created
Package and select New > Class. As this will be our main script, so do not forget to click the check
box for public static void main(string [ ]args) while creating class.
3. Write the Selenium WebDriver test case for the below mentioned steps:
Step 1 Open a Browser
Step 2 Navigate to URL
Step 3 Click on My Account button
Step 4 Enter Username
Step 5 Enter Password
Step 6 Click on LogIn button
Step 7 Click on LogOut button
Step 8 Close the Browser
1 package executionEngine;
2
3 import java.util.concurrent.TimeUnit;
4 import org.openqa.selenium.*;
5 import org.openqa.selenium.firefox.FirefoxDriver;
6
7 public class DriverScript {
8 private static WebDriver driver = null;
9 public static void main(String[] args) {
10 driver = new FirefoxDriver();
11 driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
12 driver.get("http://www.store.demoqa.com");
13
14 driver.findElement(By.xpath(".//*[@id='account']/a")).click();
15 driver.findElement(By.id("log")).sendKeys("testuser_3");
16 driver.findElement(By.id("pwd")).sendKeys("Test@123");
17 driver.findElement(By.id("login")).click();
18 driver.findElement (By.xpath(".//*[@id='account_logout']/a")).click();
19 driver.quit();
20 }
21 }
Try giving it a run. From next chapter we will start setting up the Keyword Driven Framework by
following step by step tutorial.
Once you are done with your basic test, next thing you need to do is to step up Action Keywords for
your test steps and record them in to the Excel sheet. After that a separate class will be created for
Action Keywords, so that they can be easily callable in the test with following the keyword driven
methology.
1 package config;
3 import java.util.concurrent.TimeUnit;
5 import org.openqa.selenium.By;
6 import org.openqa.selenium.WebDriver;
7 import org.openqa.selenium.firefox.FirefoxDriver;
8
10
12
14 driver=new FirefoxDriver();
15 }
16
18 driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
19 driver.get("http://www.store.demoqa.com");
20 }
21
23 driver.findElement(By.xpath(".//*[@id='account']/a")).click();
24 }
25
27 driver.findElement(By.id("log")).sendKeys("testuser_3");
28 }
29
31 driver.findElement(By.id("pwd")).sendKeys("Test@123");
32 }
33
35 driver.findElement(By.id("login")).click();
36 }
37
39 Thread.sleep(5000);
40 }
41
43 driver.findElement (By.xpath(".//*[@id='account_logout']/a")).click();
44 }
45
47 driver.quit();
48 }
49
50 }
To run the driverScript with above code, it is required to change the code of main driver script. Next
chapter is all about setting up the Driver Script class with Data Engine excel.
In last chapter, we created Action Keywords and placed them in to the DataEngine
excel sheet, now we need Apache POI in place to connect with the excel sheet in the
Selenium Test.
1 package utility;
2
3 import java.io.FileInputStream;
4 import org.apache.poi.xssf.usermodel.XSSFCell;
5 import org.apache.poi.xssf.usermodel.XSSFSheet;
6 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
7 public class ExcelUtils {
8 private static XSSFSheet ExcelWSheet;
9 private static XSSFWorkbook ExcelWBook;
10 private static XSSFCell Cell;
11
12 //This method is to set the File path and to open the Excel file
13 //Pass Excel Path and SheetName as Arguments to this method
14 public static void setExcelFile(String Path,String SheetName) throws Exception {
15 FileInputStream ExcelFile = new FileInputStream(Path);
16 ExcelWBook = new XSSFWorkbook(ExcelFile);
17 ExcelWSheet = ExcelWBook.getSheet(SheetName);
18 }
19
20 //This method is to read the test data from the Excel cell
21 //In this we are passing parameters/arguments as Row Num and Col Num
22 public static String getCellData(int RowNum, int ColNum) throws Exception{
23 Cell = ExcelWSheet.getRow(RowNum).getCell(ColNum);
24 String CellData = Cell.getStringCellValue();
25 return CellData;
26 }
27
28 }
Now Modify your main DriverScript. With the help of Excel Utility, open the Excel file,
read Action Keywords one by one and on each Action Keyword perform the required
step.
1 package executionEngine;
2
3 import config.ActionKeywords;
4 import utility.ExcelUtils;
5
6 public class DriverScript {
7
8 public static void main(String[] args) throws Exception {
9 // Declaring the path of the Excel file with the name of the Excel file
10 String sPath = "D://Tools QA Projects//trunk//Hybrid Keyword Driven//src//dataEngine//DataEngine.xlsx";
11
12 // Here we are passing the Excel path and SheetName as arguments to connect with Excel file
13 ExcelUtils.setExcelFile(sPath, "Test Steps");
14
15 //Hard coded values are used for Excel row & columns for now
16 //In later chapters we will replace these hard coded values with varibales
17 //This is the loop for reading the values of the column 3 (Action Keyword) row by row
18 for (int iRow=1;iRow<=9;iRow++){
19 //Storing the value of excel cell in sActionKeyword string variable
20 String sActionKeyword = ExcelUtils.getCellData(iRow, 3);
21
22 //Comparing the value of Excel cell with all the project keywords
23 if(sActionKeyword.equals("openBrowser")){
24 //This will execute if the excel cell value is 'openBrowser'
25 //Action Keyword is called here to perform action
26 ActionKeywords.openBrowser();}
27 else if(sActionKeyword.equals("navigate")){
28 ActionKeywords.navigate();}
29 else if(sActionKeyword.equals("click_MyAccount")){
30 ActionKeywords.click_MyAccount();}
31 else if(sActionKeyword.equals("input_Username")){
32 ActionKeywords.input_Username();}
33 else if(sActionKeyword.equals("input_Password")){
34 ActionKeywords.input_Password();}
35 else if(sActionKeyword.equals("click_Login")){
36 ActionKeywords.click_Login();}
37 else if(sActionKeyword.equals("waitFor")){
38 ActionKeywords.waitFor();}
39 else if(sActionKeyword.equals("click_Logout")){
40 ActionKeywords.click_Logout();}
41 else if(sActionKeyword.equals("closeBrowser")){
42 ActionKeywords.closeBrowser();}
43
44 }
45 }
46 }
Here we are done with our initial set up of Keyword Driven Framework.The only idea
behind the Keyword Driven framework is to accept the action keywords from the Excel,
so that all the test cases can be easily created in Excel file. But this Framework is just a
draft version. There are plenty of things can be done on it to make it more robust and
effective. In following chapters we will enhance this draft version.
In Previous Chapter we have seen that to perform any Action, we need to compare the value taken
from Excel sheet with the value of each method in Action Keyword class. Till the time there are just a
few methods, this technique would work fine. But think of a scenario where a new actions is adding
almost daily in framework. It will be tedious task to first add a new method in ActionKeyword class
then add that method in to compare statement of DriverEngine test. Think of the size of the list
of IF/ELSE loop after few releases.
Let me again tell you the need of it in other words, so that the reason can be understood. As of now in
the framework, whenever there is an addition of any new method in Action Keyword class, it is
required to put that newly created method in the if/else loop of the main Driver Script. Just to avoid
that situation it is required to use Java Reflection class, so that when a new method is added, this
reflection class will load all the methods of Action Keyword class at run time.
1 package config;
3 import java.util.concurrent.TimeUnit;
5 import org.openqa.selenium.By;
6 import org.openqa.selenium.WebDriver;
7 import org.openqa.selenium.firefox.FirefoxDriver;
12 driver=new FirefoxDriver();
13 }
14
16 driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
17 driver.get("http://www.store.demoqa.com");
18 }
19
21 driver.findElement(By.xpath(".//*[@id='account']/a")).click();
22 }
23
25 driver.findElement(By.id("log")).sendKeys("testuser_3");
26 }
27
29 driver.findElement(By.id("pwd")).sendKeys("Test@123");
30 }
31
33 driver.findElement(By.id("login")).click();
34 }
35
37 Thread.sleep(5000);
38 }
39
41 driver.findElement (By.xpath(".//*[@id='account_logout']/a")).click();
42 }
43
45 driver.quit();
46 }
47
48 }
Note: There is no change in the Action Keyword class, it is same as like in last chapter.
1 package executionEngine;
3 import java.lang.reflect.Method;
4 import config.ActionKeywords;
5 import utility.ExcelUtils;
15
19 //This will load all the methods of the class 'ActionKeywords' in it.
20 //It will be like array of method, use the break point here and do the watch
21 method = actionKeywords.getClass().getMethods();
22 }
23
25
26 //Declaring the path of the Excel file with the name of the Excel file
28
29 //Here we are passing the Excel path and SheetName to connect with the Excel file
30 //This method was created in the last chapter of 'Set up Data Engine'
32
33 //Hard coded values are used for Excel row & columns for now
34 //In later chapters we will use these hard coded value much efficiently
35 //This is the loop for reading the values of the column 3 (Action Keyword) row by row
36 //It means this loop will execute all the steps mentioned for the test case in Test Steps sheet
38 //This to get the value of column Action Keyword from the excel
42 //So this statement is doing nothing but calling that piece of code to execute
43 execute_Actions();
44 }
45 }
46
48 //As it is completely different set of logic, which revolves around the action only,
49 //It makes sense to keep it separate from the main driver script
53 //method variable contain all the method and method.length returns the total number of methods
55 //This is now comparing the method name with the ActionKeyword value got from excel
56 if(method[i].getName().equals(sActionKeyword)){
58 method[i].invoke(actionKeywords);
59 //Once any method is executed, this break statement will take the flow outside of for loop
60 break;
61 }
62 }
63 }
64 }
The above code is now much more clear and simple. If there is any addition of method in Action
Keyword class, driver script will not have any effect of it. It will automatically consider the newly
created method.
You must have noticed that we are using Action Keywords like click_MyAccount(), which is not at
all a good practice. As there will be thousand of elements in any application and to click those
elements we have to write thousands of click action keywords. So ideally there will be just one click
action which should work on every other element on the test application. To achieve that, it is needed
to separate the action from the object. For e.g. there will be a object called MyAccount and
an action called click() and it would work like this: MyAccount.click()
So our next task is to separate all the objects from the actions. To achieve that we need to create
an Object Repository, which will hold all the objects properties in it and then those properties can be
used in the main driver script. We can easily do this with the help of Property file. Normally, Java
properties file is used to store project configuration data or settings. In this tutorial, we will show you
how to set up and use a properties file. Time for action now.
2 btn_MyAccount=.//*[@id='account']/a
3 btn_LogOut=.//*[@id='account_logout']
6 txtbx_UserName=.//*[@id='log']
7 txtbx_Password=.//*[@id='pwd']
8 btn_LogIn=.//*[@id='login']
1 package config;
3 import java.util.concurrent.TimeUnit;
6 import org.openqa.selenium.By;
7 import org.openqa.selenium.WebDriver;
8 import org.openqa.selenium.firefox.FirefoxDriver;
11
13
14 //All the methods in this class now accept 'Object' name as an argument
16 driver=new FirefoxDriver();
17 }
18
20 driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
21 driver.get(Constants.URL);
22 }
23
25 //This is fetching the xpath of the element from the Object Repository property file
26 driver.findElement(By.xpath(OR.getProperty(object))).click();
27 }
28
30 driver.findElement(By.xpath(OR.getProperty(object))).sendKeys(Constants.UserName);
31 }
32
34 driver.findElement(By.xpath(OR.getProperty(object))).sendKeys(Constants.Password);
35 }
36
38 Thread.sleep(5000);
39 }
40
42 driver.quit();
43 }
44
45 }
Note: We have still used input_Password() and not detached this object from action. We will take
care of this in next coming chapter of Data Driven.
Note: If you see carefully, object argument is passed in every method, even if it is not required in the
method, such as closeBrowser(). This is the mandatory condition of the reflection class that all the
methods will have same arguments, even if the argument is not used in some methods.
1 package config;
2
10
18
21
25
26 }
3 import java.io.FileInputStream;
4 import java.lang.reflect.Method;
5 import java.util.Properties;
7 import config.ActionKeywords;
8 import config.Constants;
9 import utility.ExcelUtils;
10
12
18
21 method = actionKeywords.getClass().getMethods();
22 }
23
25
27 ExcelUtils.setExcelFile(Path_DataEngine, Constants.Sheet_TestSteps);
28
35 //Loading all the properties from Object Repository property file in to OR object
36 OR.load(fs);
37
38
42 execute_Actions();
43 }
44 }
45
47
48 for(int i=0;i<method.length;i++){
49 if(method[i].getName().equals(sActionKeyword)){
51 //Passing 'Page Object' name and 'Action Keyword' as Arguments to this method
52 method[i].invoke(actionKeywords,sPageObject);
53 break;
54 }
55 }
56 }
57 }
Note: Name of the object in the OR file is case sensitive, it has to matched exactly the same way it is
mentioned in the DataEngine sheet.
Project folder would look like this:
In the last chapter of Exception handling we learned how to deal with exceptions in the framework. In
all the methods of Action Keyword class and Excel Utils class, try catch block is set up. So now
the framework is forced to eat all the exceptions and forced to change the value of bresult boolean
variable to false. In this chapter we will learn to handle the situation when the bResult variable is
false.
The whole point of setting the bResult variable to false is to stop the execution of the test case and
mark the test case as failed.
How to do it
Step 1: Create an extra column in the Test Case sheet and name it as Results
Step 2: Create another extra column in Test Steps sheet and name it as Results
Step 3: Create two new Constants variables for the results column of Test Case sheet and
Test Step sheet
Step 4: Create two new Constants variables for the Pass results & Fail result
1 @SuppressWarnings("static-access")
3 //This method accepts four arguments (Result, Row Number, Column Number & Sheet Name)
4 public static void setCellData(String Result, int RowNum, int ColNum, String SheetName) throws Exception {
5 try{
7 ExcelWSheet = ExcelWBook.getSheet(SheetName);
8 Row = ExcelWSheet.getRow(RowNum);
10 if (Cell == null) {
11 Cell = Row.createCell(ColNum);
12 Cell.setCellValue(Result);
13 } else {
14 Cell.setCellValue(Result);
15 }
16 // Constant variables Test Data path and Test Data file name
18 ExcelWBook.write(fileOut);
19 //fileOut.flush();
20 fileOut.close();
22 }catch(Exception e){
23 DriverScript.bResult = false;
24 }
25 }
Step 6: Modify the main Driver Script:
1 package executionEngine;
3 import java.io.FileInputStream;
4 import java.lang.reflect.Method;
5 import java.util.Properties;
6 import org.apache.log4j.xml.DOMConfigurator;
7 import config.ActionKeywords;
8 import config.Constants;
9 import utility.ExcelUtils;
10 import utility.Log;
11
13
24
27 method = actionKeywords.getClass().getMethods();
28 }
29
33 ExcelUtils.setExcelFile(Constants.Path_TestData);
34 DOMConfigurator.configure("log4j.xml");
38 OR.load(fs);
39
41 startEngine.execute_TestCase();
42 }
43
44 //Second method, this is to figure out the test cases execution one by one
48 for(int iTestcase=1;iTestcase<iTotalTestCases;iTestcase++){
49 //Setting the value of bResult variable to 'true' before starting every test case
50 bResult = true;
61 for (;iTestStep<iTestLastStep;iTestStep++){
62 sActionKeyword = ExcelUtils.getCellData(iTestStep,
Constants.Col_ActionKeyword,Constants.Sheet_TestSteps);
63
sPageObject = ExcelUtils.getCellData(iTestStep, Constants.Col_PageObject,
64 Constants.Sheet_TestSteps);
65 execute_Actions();
66 //This is the result code, this code will execute after each test step
67 //The execution flow will go in to this only if the value of bResult is 'false'
68 if(bResult==false){
70
ExcelUtils.setCellData(Constants.KEYWORD_FAIL,iTestcase,Constants.Col_Result,Constants.Sheet_TestCases);
71
//End the test case in the logs
72
Log.endTestCase(sTestCaseID);
73
//By this break statement, execution flow will not execute any
74 more test step of the failed test case
75 break;
76 }
77
78 }
79 //This will only execute after the last step of the test case, if value is not 'false' at any step
80
if(bResult==true){
81
//Storing the result as Pass in the excel sheet
82
83 ExcelUtils.setCellData(Constants.KEYWORD_PASS,iTestcase,Constants.Col_Result,Constants.Sheet_TestCases);
84 Log.endTestCase(sTestCaseID);
85 }
86 }
87 }
88 }
89
91
92 for(int i=0;i<method.length;i++){
93
94 if(method[i].getName().equals(sActionKeyword)){
95 method[i].invoke(actionKeywords,sPageObject);
97 if(bResult==true){
98 //If the executed test step value is true, Pass the test step in Excel sheet
99 ExcelUtils.setCellData(Constants.KEYWORD_PASS, iTestStep,
Constants.Col_TestStepResult, Constants.Sheet_TestSteps);
100
break;
101
}else{
102
//If the executed test step value is false, Fail the test step in Excel sheet
103
ExcelUtils.setCellData(Constants.KEYWORD_FAIL, iTestStep,
104 Constants.Col_TestStepResult, Constants.Sheet_TestSteps);
105 //In case of false, the test execution will not reach to last step of closing browser
106 //So it make sense to close the browser before moving on to next test case
107 ActionKeywords.closeBrowser("");
108 break;
Try giving it a run and see if it works fine on your system. Once you done that try changing the xpath
of any object and see the framework handles the failed test case well or not.
1 package config;
3 import java.util.concurrent.TimeUnit;
5 import org.openqa.selenium.By;
6 import org.openqa.selenium.WebDriver;
7 import org.openqa.selenium.chrome.ChromeDriver;
8 import org.openqa.selenium.firefox.FirefoxDriver;
9 import org.openqa.selenium.ie.InternetExplorerDriver;
10 import executionEngine.DriverScript;
11 import utility.Log;
12
14
18 Log.info("Opening Browser");
19 try{
22 driver=new FirefoxDriver();
24 }
25 else if(data.equals("IE")){
27 driver=new InternetExplorerDriver();
29 }
30 else if(data.equals("Chrome")){
31 driver=new ChromeDriver();
33 }
34
35 int implicitWaitTime=(10);
36 driver.manage().timeouts().implicitlyWait(implicitWaitTime, TimeUnit.SECONDS);
39 DriverScript.bResult = false;
40 }
41 }
42
44 try{
45 Log.info("Navigating to URL");
46 driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
48 driver.get(Constants.URL);
49 }catch(Exception e){
51 DriverScript.bResult = false;
52 }
53 }
54
56 try{
58 driver.findElement(By.xpath(OR.getProperty(object))).click();
59 }catch(Exception e){
61 DriverScript.bResult = false;
62 }
63 }
64 //Now this method accepts two value (Object name & Data)
66 try{
68 driver.findElement(By.xpath(OR.getProperty(object))).sendKeys(data);
69 }catch(Exception e){
71 DriverScript.bResult = false;
72 }
73 }
74
76 try{
78 Thread.sleep(5000);
79 }catch(Exception e){
81 DriverScript.bResult = false;
82 }
83 }
84
85 public static void closeBrowser(String object, String data){
86 try{
88 driver.quit();
89 }catch(Exception e){
91 DriverScript.bResult = false;
92 }
93 }
94
95 }
1 package executionEngine;
3 import java.io.FileInputStream;
4 import java.lang.reflect.Method;
5 import java.util.Properties;
6 import org.apache.log4j.xml.DOMConfigurator;
7 import config.ActionKeywords;
8 import config.Constants;
9 import utility.ExcelUtils;
10 import utility.Log;
11
13
14 public static Properties OR;
25
28 method = actionKeywords.getClass().getMethods();
29 }
30
32 ExcelUtils.setExcelFile(Constants.Path_TestData);
33 DOMConfigurator.configure("log4j.xml");
37 OR.load(fs);
38
40 startEngine.execute_TestCase();
41 }
42
45 for(int iTestcase=1;iTestcase<iTotalTestCases;iTestcase++){
46 bResult = true
62 execute_Actions();
63 if(bResult==false){
64
ExcelUtils.setCellData(Constants.KEYWORD_FAIL,iTestcase,Constants.Col_Result,Constants.Sheet_TestCases);
65
Log.endTestCase(sTestCaseID);
66
break;
67
}
68
}
69
if(bResult==true){
70
71 ExcelUtils.setCellData(Constants.KEYWORD_PASS,iTestcase,Constants.Col_Result,Constants.Sheet_TestCases);
72 Log.endTestCase(sTestCaseID);
73 }
74
75 }
76
77 }
78 }
79
81
82 for(int i=0;i<method.length;i++){
83
84 if(method[i].getName().equals(sActionKeyword)){
86 method[i].invoke(actionKeywords,sPageObject, sData);
87 if(bResult==true){
88 ExcelUtils.setCellData(Constants.KEYWORD_PASS, iTestStep,
Constants.Col_TestStepResult, Constants.Sheet_TestSteps);
89
break;
90
}else{
91
ExcelUtils.setCellData(Constants.KEYWORD_FAIL, iTestStep,
92 Constants.Col_TestStepResult, Constants.Sheet_TestSteps);
93 ActionKeywords.closeBrowser("","");
94 break;
95 }
Note: For any explanation on un-commented code, please refer previous chapters.
You can see now the whole Keyword Driven Framework is set for use. Now it is up to you to
implement other enhancements in this framework like you can implement HTML reporting in it or you
can even implement some sort of automatic email reply on any test fail or an automatic email sent to
the project stakeholders with test execution results or any thing.
But for me the next chapter is dam so important, so do not wait just jump on it.
The overall idea behind the Keyword Driven Framework is to utilize manual testers to write
automation scripts. Given the fact that keywords are so closely resemble a manual test procedure, it
becomes simpler to trace actions in automated tests to actions in manual tests. Working with
keywords data tables for everyday application automation is a lot less technical than working with
code statements. Therefore individuals that are not as technical can be brought onto the team to help
in creating automated tests.
But in order to effectively implement a Keyword framework, reliance on intuition must be reduced,
while reliance on standards must be increased. While some standards are automatically imposed, with
this type of framework, many standards are not, so theres an ongoing effort to ensure resources are
aware of standards, understand them, and are able to effectively implement them.
So the best practice in Keyword Driven framework is to impose the standards automatically, so that
the gap of discrepancy can be reduced. Let me take an example and explain it to you. There is a page
object called txtbx_UserName which represent the Username text box in the application. To
effectively use it in the keyword driven framework, we write the same name in the data engine sheet.
When execution engine reads txtbx_UserName, it knows which object to point from the Object
Repository property file. But this txtbx_UserName is case sensitive, any spelling error in this like
txtbox_UserName would result in an exception.
One of the drawback of the Keyword framework is that it is developed by different set of people who
are more technical and it is used by different set of people who are not very technical, so there is
always a gap. To finish the gap, it is better to impose standards. Means if we can force data engine
sheet in a way, so that the user would not be able to enter any invalid object, which result in to
exceptions.
One more example will explain the situation logically. As we know that there are many continue
buttons on any e-commerce application. Actually almost on every page of an e-commerce application
you would find a continue button. Now as a user of keyword framework, it is difficult to identify the
right continue button he/she would require to click. And it is not the best practice to name continue
button like continue_1 & continue_2, even in this case it would be confusing because the user has
not developed the framework.
This chapter will allow you to avoid any such situations where a user can make mistakes unknowingly.
3) Now create new columns for the objects of each Page in the application.
4) Mention all the page objects under the respective page name columns.
5) Create a new column and name it as Action Keywords and mention all the action
keywords under it.
6) Select the range of Page Name column and name the range as Page_Name.
7) Select the range of Home Page objects and name the range as Home_Page.
8) Do the above steps for LogIn Page objects & Action Keywords also.
2) Select the range of the column Page Name, go to Data tab and then click on Data Validation
drop down and select DataValidation.
3) Select List from the Allow drop down and enter =Page_Name in the Source text box.
Now if you see that when you click on any row of column Page Name, you would get a drop down list
populating all the page name available in the application. This will ensure that the user would not be
able to make any choice which can not be handled with the framework.
4) Do the same for Action Keywords as well and it will display all the actionsavailable to use.
Note: If in case you face any issue in setting up this data trick, you follow this link:
http://www.contextures.com/xlDataVal02.html
I hope that you have enjoyed the journey of Step by step tutorial of setting up Keyword Driven
Framework with Selenium WebDriver so far and you have understood all the topics well. Lets revise
what we have covered and do a Practice Exercise on it.
Practice Exercise
Before jumping to the next level I would like to do an exercise on what we have learned so far on
the Demo Application. What we have covered so far is the Login functionality only. I would like you to
automate an end to end flow covering below steps:
1. Login to the demo application Online Store
2. Selecting a product category from Top Menu
3. Selecting a product and adding it to the cart
4. Go to payment details page and complete the order
5. Verify details from final Confirmation page
Once you done with the above exercise, please send me your code so that I can share it
with wider audience with your name.
Project Download
Please download the code from here Selenium Automation Keyword Driven Framework
Or please read the code below.
Package: executionEngine
Class: DriverScript
1 package executionEngine;
3 import java.io.FileInputStream;
4 import java.lang.reflect.Method;
5 import java.util.Properties;
7 import org.apache.log4j.xml.DOMConfigurator;
9 import config.ActionKeywords;
10 import config.Constants;
11 import utility.ExcelUtils;
12 import utility.Log;
13
15
21
28
31 method = actionKeywords.getClass().getMethods();
32 }
33
35 ExcelUtils.setExcelFile(Constants.Path_TestData);
36 DOMConfigurator.configure("log4j.xml");
40 OR.load(fs);
41
43 startEngine.execute_TestCase();
44
45 }
46
49 for(int iTestcase=1;iTestcase<iTotalTestCases;iTestcase++){
50 bResult = true;
65 execute_Actions();
66 if(bResult==false){
67
ExcelUtils.setCellData(Constants.KEYWORD_FAIL,iTestcase,Constants.Col_Result,Constants.Sheet_TestCases);
68
Log.endTestCase(sTestCaseID);
69
break;
70
}
71
72 }
73 if(bResult==true){
74
ExcelUtils.setCellData(Constants.KEYWORD_PASS,iTestcase,Constants.Col_Result,Constants.Sheet_TestCases);
75
76 Log.endTestCase(sTestCaseID);
77 }
78 }
79 }
80 }
81
83
84 for(int i=0;i<method.length;i++){
85
86 if(method[i].getName().equals(sActionKeyword)){
87 method[i].invoke(actionKeywords,sPageObject, sData);
88 if(bResult==true){
89 ExcelUtils.setCellData(Constants.KEYWORD_PASS, iTestStep,
Constants.Col_TestStepResult, Constants.Sheet_TestSteps);
90
break;
91
}else{
92
ExcelUtils.setCellData(Constants.KEYWORD_FAIL, iTestStep,
93 Constants.Col_TestStepResult, Constants.Sheet_TestSteps);
94 ActionKeywords.closeBrowser("","");
95 break;
Package: config
Class: Action Keywords
1
package config;
2
3
import java.util.concurrent.TimeUnit;
4
5
import static executionEngine.DriverScript.OR;
6
7
import org.openqa.selenium.By;
8
import org.openqa.selenium.WebDriver;
9
import org.openqa.selenium.chrome.ChromeDriver;
10
import org.openqa.selenium.firefox.FirefoxDriver;
11
import org.openqa.selenium.ie.InternetExplorerDriver;
12
13
import executionEngine.DriverScript;
14
import utility.Log;
15
16
public class ActionKeywords {
17
18
public static WebDriver driver;
19
20
public static void openBrowser(String object,String data){
21
Log.info("Opening Browser");
22
try{
23
if(data.equals("Mozilla")){
24
driver=new FirefoxDriver();
25
Log.info("Mozilla browser started");
26
}
27
28 else if(data.equals("IE")){
30 driver=new InternetExplorerDriver();
32 }
33 else if(data.equals("Chrome")){
35 driver=new ChromeDriver();
37 }
38
39 int implicitWaitTime=(10);
40 driver.manage().timeouts().implicitlyWait(implicitWaitTime, TimeUnit.SECONDS);
43 DriverScript.bResult = false;
44 }
45 }
46
48 try{
49 Log.info("Navigating to URL");
50 driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
51 driver.get(Constants.URL);
52 }catch(Exception e){
54 DriverScript.bResult = false;
55 }
56 }
57
59 try{
60 Log.info("Clicking on Webelement "+ object);
61 driver.findElement(By.xpath(OR.getProperty(object))).click();
62 }catch(Exception e){
64 DriverScript.bResult = false;
65 }
66 }
67
69 try{
71 driver.findElement(By.xpath(OR.getProperty(object))).sendKeys(data);
72 }catch(Exception e){
74 DriverScript.bResult = false;
75 }
76 }
77
79 try{
81 Thread.sleep(5000);
82 }catch(Exception e){
84 DriverScript.bResult = false;
85 }
86 }
87
89 try{
91 driver.quit();
92 }catch(Exception e){
94 DriverScript.bResult = false;
95 }
96 }
97
Class: Constants
1 package config;
5 //System Variables
12
22
26
27 }
2 btn_MyAccount=.//*[@id='account']/a
3 btn_LogOut=.//*[@id='account_logout']/a
6 txtbx_UserName=.//*[@id='log']
7 txtbx_Password=.//*[@id='pwd']
8 btn_LogIn=.//*[@id='login']
Package: dataEngine
Sheet: Test Case
Sheet: Test Steps
Sheet: Settings
Package: Utility
Class: ExcelUtils
1 package utility;
3 import java.io.FileInputStream;
4 import java.io.FileOutputStream;
6 import org.apache.poi.xssf.usermodel.XSSFSheet;
7 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
8 import org.apache.poi.xssf.usermodel.XSSFRow;
10 import config.Constants;
11 import executionEngine.DriverScript;
18
20 try {
25 DriverScript.bResult = false;
26 }
27 }
28
29 public static String getCellData(int RowNum, int ColNum, String SheetName ) throws Exception{
30 try{
31 ExcelWSheet = ExcelWBook.getSheet(SheetName);
32 Cell = ExcelWSheet.getRow(RowNum).getCell(ColNum);
34 return CellData;
37 DriverScript.bResult = false;
38 return"";
39 }
40 }
41
43 int iNumber=0;
44 try {
45 ExcelWSheet = ExcelWBook.getSheet(SheetName);
46 iNumber=ExcelWSheet.getLastRowNum()+1;
49 DriverScript.bResult = false;
50 }
51 return iNumber;
52 }
53
54 public static int getRowContains(String sTestCaseName, int colNum,String SheetName) throws Exception{
55 int iRowNum=0;
56 try {
57 //ExcelWSheet = ExcelWBook.getSheet(SheetName);
61 break;
62 }
63 }
66 DriverScript.bResult = false;
67 }
68 return iRowNum;
69 }
70
71 public static int getTestStepsCount(String SheetName, String sTestCaseID, int iTestCaseStart) throws Exception{
72 try {
73 for(int i=iTestCaseStart;i<=ExcelUtils.getRowCount(SheetName);i++){
75 int number = i;
76 return number;
77 }
78 }
79 ExcelWSheet = ExcelWBook.getSheet(SheetName);
80 int number=ExcelWSheet.getLastRowNum()+1;
81 return number;
84 DriverScript.bResult = false;
85 return 0;
86 }
87 }
88
89 @SuppressWarnings("static-access")
90 public static void setCellData(String Result, int RowNum, int ColNum, String SheetName) throws Exception {
91 try{
92
93 ExcelWSheet = ExcelWBook.getSheet(SheetName);
94 Row = ExcelWSheet.getRow(RowNum);
96 if (Cell == null) {
97 Cell = Row.createCell(ColNum);
98 Cell.setCellValue(Result);
99 } else {
100 Cell.setCellValue(Result);
101 }
103 ExcelWBook.write(fileOut);
104 //fileOut.flush();
105 fileOut.close();
109
110 }
111 }
112
113 }
Class: Log
1 package utility;
3 import org.apache.log4j.Logger;
4
5 public class Log {
10 // This is to print log for the beginning of the test case, as we usually run so many test cases as a test suite
12
13 Log.info("****************************************************************************************");
14 Log.info("****************************************************************************************");
16 Log.info("****************************************************************************************");
17 Log.info("****************************************************************************************");
18
19 }
20
24 Log.info("X");
25 Log.info("X");
26 Log.info("X");
27 Log.info("X");
28
29 }
30
33 Log.info(message);
34 }
35
38 }
39
41 Log.error(message);
42 }
43
45 Log.fatal(message);
46 }
47
49 Log.debug(message);
50 }
51
52 }
Project Folder