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.
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 arithmetic calculation, date calculation, string manipulation, etc. should be avoided in the Test scripts rather put them into the functions and use them.
Benefits of User-Defined Functions
- It can be used in a number of places without rewriting the code.
- The 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.
- Function One: openBrowser(int iTestCaseRow), it will return a WebDriver
- Function Two: getTestCaseName(String sTestCase), it will return refined Test case name
- 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...
- Create a new column (Browser) in the Test Data sheet.
Make some entries in the Constant class for the column numbers:
package utility;
public class Constant {
public static final String URL = "https://www.store.demoqa.com";
public static final String Path_TestData = "D://ToolsQA//OnlineStore//src//testData//";
public static final String File_TestData = "TestData.xlsx";
//Test Data Sheet Columns
public static final int Col_TestCaseName = 0;
public static final int Col_UserName =1 ;
public static final int Col_Password = 2;
public static final int Col_Browser = 3;
}
- 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).
public class Utils {
public static WebDriver driver = null;
public static WebDriver openBrowser(int iTestCaseRow) throws Exception{
String sBrowserName;
try{
sBrowserName = ExcelUtils.getCellData(iTestCaseRow, Constant.Col_Browser);
if(sBrowserName.equals("Mozilla")){
driver = new FirefoxDriver();
Log.info("New driver instantiated");
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
Log.info("Implicit wait applied on the driver for 10 seconds");
driver.get(Constant.URL);
Log.info("Web application launched successfully");
}
}catch (Exception e){
Log.error("Class Utils | Method OpenBrowser | Exception desc : "+e.getMessage());
}
return driver;
}
}
- 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 into UDF_TC.
public static String getTestCaseName(String sTestCase)throws Exception{
String value = sTestCase;
try{
int posi = value.indexOf("@");
value = value.substring(0, posi);
posi = value.lastIndexOf(".");
value = value.substring(posi + 1);
return value;
}catch (Exception e){
Log.error("Class Utils | Method getTestCaseName | Exception desc : "+e.getMessage());
throw (e);
}
- Once Test Case name is captured, it can be used as an Argument for a function that will return the Test case row from the Excel sheet.
public static int getRowContains(String sTestCaseName, int colNum) throws Exception{
int i;
try {
int rowCount = ExcelWSheet.getLastRowNum();
for ( i=0 ; i<rowCount; i++){
if (ExcelUtils.getCellData(i,colNum).equalsIgnoreCase(sTestCaseName)){
break;
}
}
return i;
}catch (Exception e){
Log.error("Class ExcelUtil | Method getRowContains | Exception desc : " + e.getMessage());
throw(e);
}
}
- Create a 'New Class' by right click on the ‘automationFramework‘ package then select TestNG > Create a TestNG Class and name it as UDF_TC.
Note: Take previous executed test case 'TestNG_Framework' and modify its Before Method only. The new test script will look like this:
package automationFramework;
import org.apache.log4j.xml.DOMConfigurator;
import org.openqa.selenium.WebDriver;
import org.testng.annotations.*;
import pageObjects.*;
import utility.*;
import appModules.*;
public class UDF_TC {
public WebDriver driver;
private String sTestCaseName;
private int iTestCaseRow;
@BeforeMethod
public void beforeMethod() throws Exception {
DOMConfigurator.configure("log4j.xml");
sTestCaseName = this.toString();
sTestCaseName = Utils.getTestCaseName(this.toString());
Log.startTestCase(sTestCaseName);
ExcelUtils.setExcelFile(Constant.Path_TestData + Constant.File_TestData,"Sheet1");
iTestCaseRow = ExcelUtils.getRowContains(sTestCaseName,Constant.Col_TestCaseName);
driver = Utils.openBrowser(iTestCaseRow);
}
@Test
public void main() throws Exception {
SignIn_Action.Execute(driver);
System.out.println("Login Successfully, now it is the time to Log Off buddy.");
Home_Page.lnk_LogOut(driver).click();
Log.info("Click action is performed on Log Out link");
}
@AfterMethod
public void afterMethod() {
driver.quit();
}
}
Isn't it easy to call functions rather than writing them again and again and increase code complexity.