SeleniumWebdriver - Page objects Implementation - Part 1
SeleniumWebdriver - Page objects Implementation - Part 2
I have implemented
complex QTP hybrid frameworks. Now I am working on Selenium2 aka. Selenium Webdriver and implemented the similar framework. Why? Open source, No licence fee, multi browser os language support.
I would like to share my experience through this post.
I take into consideration following points while designing the framework.
1. Re-usability - Any change in the application (Change in the object property) that change need to be done at one place only, if we are doing at more than one place it is not re-usable code, there are slight exceptions.
2. Independent modules -
3. Easy to use - Selecting the keywords from the auto suggest, not required any programming knowledge to create the test case.
4. Multi-level abstraction -
5. Run single, multiple and selected test cases.
Following are the challenges that I came across during implementation.
1. Email Notifications of test results - Initially I have used
Hudson CI to schedule the test and receive email notifications. IE Driver is not stable in few scenarios like Modal-Dialog, it keep on waiting for ever without moving ahead, user need to close the IEs and restart the test again. There is no option of sending attachments through Hudson. So I started invoking the ANT using .VBS where I have better control of the execution and I can kill the process if it is not responding. Email notification component is written in VBS, where I can send email with attachments with intermediate test status (I need not require to wait for hours to get the results, there is an option that than be set so that results are generated after executing every 20 test cases) . Any .vbs file can be invoked easily through Java. Attaching the email notification screen shot below.
2. Building JAR file - You have option to execute the test directly on eclipse. When it is scheduled we need to compile all the files into a single JAR file so that it can be invoked using ANT and easily distributed to other systems. Build.xml is created to handle all these activities.
3. TestNG - Pass/Fail/Skipped test cases count is recorded using TestNG, but this report is generated after completion of all the methods. Lets assume we ran test for 10 hours, browser or Selenium don't respond; all your test results are lost. Implemented intermediate test status update using VBS, so that even the application crashed at-least I can get the results till the test executed.
4. Screenshot on Failure - Take screen shot and send it in the email along with the test results.
5. Backup the results - Before each run all the test results need to be copied in separate folder, so that results are not lot and can be verified in future. If do it manually, you may miss to copy the files.
6. Page Object Implementations - In QTP Page Objects Implementation is accomplished used dual function design. In Webdriver Page Objects are independent class where all the methods and locators of a particular page is kept in one class, this is the design feature which I like in Webdriver.
7. TestData - My project has lot of test data. Initially I have used TestNG xml and pass it as parameters. I felt it was difficult to maintain 100+ fields, so I have decided to create a new class for test data.
8. Test case log - Lets assume a single test case run for 30 min, how will you trace if some thing goes wrong in between? using logs. Statements are generated at important points like saved, deleted, ID=1234dd.... in an notepad, so that it act as a reference to compare against the actual data created.
9. Configuration Management - As many people are working on the same project, files need to be stored safely in the configuration management tool so that any conflicts can be resolved by version comparison. As .java is a text file, so it can be easily uploaded to any tool. While working with QTP I use to maintain the "Keywords" in excel files, the two major disadvantages I have noticed was (1) If the Keyword is incorrect, I will not know until the test is executed. (2) Maintaining excel sheets in an configuration management tool and performing the version comparison is not possible.
I started my carrier with
Winrunner and love the
Mercury Tours Site. This is the website on which I have learnt my first automation skills. All the page objects are created based on this site, any one can access this site.
Project folder structure screen shot below.
1. Package Mercury Tours - This is the base folder where Initilize.java, TC(Test Cases), SendEmail.Java files are stored.
Initilize.Java - File call Initilize.vbs that copies all the previous test results if there are any from ScreenShots and Test_reports folder to a backup folder.
package MercuryTours;
import java.io.File;
import org.testng.annotations.Test;
import MercuryTours.PageObjects.UtilityScript;
public class initilize extends UtilityScript {
@Test
public void Test_initilize_main() throws Exception {
File directory = new File (".");
try{Runtime.getRuntime().exec("wscript.exe "+directory.getCanonicalPath()+"\\initilize.vbs" );
}
catch(Exception e){e.printStackTrace();
}
xKillIEs();
Wait(3000);
}
}
2. TC(Test Cases) - Test case logic is written here by using page objects. All the test cases have separate files TC1, TC2....
package MercuryTours;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.support.PageFactory;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
import MercuryTours.PageObjects.UtilityScript;
import MercuryTours.PageObjects._01_Initilize;
import MercuryTours.PageObjects._02_Login;
import MercuryTours.PageObjects._03_FindAFlight;
import MercuryTours.PageObjects._04_SelectAFlight;
import MercuryTours.PageObjects._05_BookAFlight;
import MercuryTours.PageObjects._06_FlightConformation;
//@Listeners({ p2pZions.TestNG.TestNGCustom.class, p2pZions.TestNG.TestNGCustomeListener.class })
public class MercuryTours_TC_01 extends UtilityScript {
InternetExplorerDriver driver;
@BeforeClass(alwaysRun = true)
protected void setUp() throws Exception {
driver = new InternetExplorerDriver();
}
@AfterClass(alwaysRun = true)
protected void tearDown() throws Exception {
driver.quit();
xKillIEs();
}
@Test(groups = { "MercuryToursTestCases" }, enabled = true)
public void Test_E2E_01() throws Exception {
MethodName = MethodName + "TC_01-"; //Used while sending email to report the test cases executed
Method = "TC_01"; //Used while sending email to report the test cases executed
Print("Start:" + xGetDateTimeIP());
_01_Initilize Initilize = PageFactory.initElements(driver,_01_Initilize.class);
Initilize.zOpen(Url);
_02_Login Login = PageFactory.initElements(driver,_02_Login.class);
Login.zEnterCrediantials("qtp123", "qtp123");
_03_FindAFlight FindAFlight = PageFactory.initElements(driver,_03_FindAFlight.class);
FindAFlight.zTripTypeOneWay();
FindAFlight.zNumberOfPassengers("4");
FindAFlight.zDepartingFrom("London");
FindAFlight.zDepartingOnDay("2");
FindAFlight.zDepartingOnMonth("2");
FindAFlight.zArrivingIn("Seattle");
FindAFlight.zFirstClass();
FindAFlight.zContinue();
_04_SelectAFlight SelectAFlight = PageFactory.initElements(driver,_04_SelectAFlight.class);
SelectAFlight.zDepartFlightSelection();
SelectAFlight.zContinue();
_05_BookAFlight BookAFlight = PageFactory.initElements(driver,_05_BookAFlight.class);
BookAFlight.zPassengerDetails("FirstName1", "LastName1", "HNML", "0");
BookAFlight.zPassengerDetails("FirstName2", "LastName2", "HNML", "1");
BookAFlight.zPassengerDetails("FirstName3", "LastName3", "HNML", "2");
BookAFlight.zPassengerDetails("FirstName4", "LastName4", "HNML", "3");
BookAFlight.zCardDetails("123456789111");
BookAFlight.zContinue();
_06_FlightConformation FlightConformation = PageFactory.initElements(driver,_06_FlightConformation.class);
FlightConformation.zGetConformationNumber();
FlightConformation.zLogOut();
}
}
3. SendEmail.Java - This file is used to call the SendEmail.vbs file with all the executed test cases (Variable MethodName)
package MercuryTours;
import java.io.File;
import org.testng.annotations.Test;
import MercuryTours.PageObjects.UtilityScript;
public class SendEmail extends UtilityScript {
@Test
public void Test_SendEmail_main() throws InterruptedException {
Wait(3000);
File directory = new File(".");
// Print(MethodName);
try {
Runtime.getRuntime().exec(
"wscript.exe " + directory.getCanonicalPath()
+ "\\sendemail.vbs " + MethodName);
} catch (Exception e) {
e.printStackTrace();
}
}
}
4. _01_initilize.java - This file is used to open the browser, open the URL and set the implicit timeouts.
package MercuryTours.PageObjects;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
public class _01_Initilize extends UtilityScript {
private WebDriver driver;
public _01_Initilize(WebDriver driver) throws InterruptedException {
this.driver = driver;
}
public _01_Initilize zOpen(String url) throws Exception {
driver.manage().timeouts()
.implicitlyWait(ImplicitWait, TimeUnit.SECONDS);
// Code to mazimize the window. Reason some times Auto suggest,some
// objects will fail if not maximized
String script = "if (window.screen){window.moveTo(0,0);window.resizeTo(window.screen.availWidth,window.screen.availHeight);};";
((JavascriptExecutor) driver).executeScript(script);
driver.get(url);
return this;
}
}
5. _02_Login.Java - All the locators pertaining to the login page. I group similar page objects into one group so I have used _01,_02.....
package MercuryTours.PageObjects;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
public class _02_Login extends UtilityScript {
private WebDriver driver;
public _02_Login(WebDriver driver) throws InterruptedException {
this.driver = driver;
}
public _02_Login zEnterCrediantials(String UserNameTxt, String PasswordTxt)
throws InterruptedException {
Wait(3000);
driver.findElement(By.name("userName")).sendKeys(UserNameTxt);
driver.findElement(By.name("password")).sendKeys(UserNameTxt);
driver.findElement(By.name("login")).click();
Print("UserName:" + UserNameTxt);
Print("---Login");
Wait(3000);
return this;
}
}
6. _03_FindAFlight.java
package MercuryTours.PageObjects;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
public class _03_FindAFlight extends UtilityScript {
private WebDriver driver;
public _03_FindAFlight(WebDriver driver) throws InterruptedException {
this.driver = driver;
}
public void zTripTypeOneWay() throws InterruptedException {
driver.findElement(By.xpath("//input[@value='oneway']")).click();
}
public void zTripTypeRoundTrip() throws InterruptedException {
driver.findElement(By.xpath("//input[@value='roundtrip']")).click();
}
public void zNumberOfPassengers(String Values_1to4)
throws InterruptedException {
driver.findElement(
By.xpath("//select[@name='passCount']/option[@value='"
+ Values_1to4 + "']")).click();
}
public void zDepartingFrom(String DepartingPlace)
throws InterruptedException {
driver.findElement(
By.xpath("//select[@name='fromPort']/option[@value='"
+ DepartingPlace + "']")).click();
}
public void zDepartingOnMonth(String Month_1to12)
throws InterruptedException {
driver.findElement(
By.xpath("//select[@name='fromMonth']/option[@value='"
+ Month_1to12 + "']")).click();
}
public void zDepartingOnDay(String Day_1to31) throws InterruptedException {
driver.findElement(
By.xpath("//select[@name='fromDay']/option[@value='"
+ Day_1to31 + "']")).click();
}
public void zArrivingIn(String ArrivingPlace) throws InterruptedException {
driver.findElement(
By.xpath("//select[@name='toPort']/option[@value='"
+ ArrivingPlace + "']")).click();
}
public void zReturningOnMonth(String Month_1to12)
throws InterruptedException {
driver.findElement(
By.xpath("//select[@name='toMonth']/option[@value='"
+ Month_1to12 + "']")).click();
}
public void zReturingOnDay(String Day_1to31) throws InterruptedException {
driver.findElement(
By.xpath("//select[@name='toDay']/option[@value='" + Day_1to31
+ "']")).click();
}
public void zEconomyClass() throws InterruptedException {
driver.findElement(By.xpath("//input[@value='Coach']")).click();
}
public void zBusinessClass() throws InterruptedException {
driver.findElement(By.xpath("//input[@value='Business']")).click();
}
public void zFirstClass() throws InterruptedException {
driver.findElement(By.xpath("//input[@value='First']")).click();
}
public _03_FindAFlight zContinue() throws InterruptedException {
driver.findElement(By.name("findFlights")).click();
Wait(3000);
return this;
}
}
7. _04_SelectAFlight.Java
package MercuryTours.PageObjects;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
public class _04_SelectAFlight extends UtilityScript {
private WebDriver driver;
public _04_SelectAFlight(WebDriver driver) throws InterruptedException {
this.driver = driver;
}
public void zDepartFlightSelection () throws InterruptedException {
//Implement logic to choose the flight based on Airline, Price
//Selected Second option (ODD numbers 3 5 7 8 there are some blank divs between)
driver.findElement(By.xpath("//tr[5]/td/input[@name='outFlight']")).click();
}
public void zReturnFlightSelection () throws InterruptedException {
//Implement logic to choose the flight based on Airline, Price
driver.findElement(By.xpath("//input[@name='inFlight'][1]")).click();
}
public _04_SelectAFlight zContinue () throws InterruptedException {
driver.findElement(By.name("reserveFlights")).click();
Wait(3000);
return this;
}
}
8. _05_BookAFlight
package MercuryTours.PageObjects;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
public class _05_BookAFlight extends UtilityScript {
private WebDriver driver;
public _05_BookAFlight(WebDriver driver) throws InterruptedException {
this.driver = driver;
}
public void zPassengerDetails (String FirstName, String LastName, String Meal, String IndexStartFrom0) throws InterruptedException {
driver.findElement(By.name("passFirst"+IndexStartFrom0)).sendKeys(FirstName);
driver.findElement(By.name("passLast"+IndexStartFrom0)).sendKeys(LastName);
driver.findElement(By.xpath("//select[@name='pass."+IndexStartFrom0+".meal']/option[@value='"+ Meal +"']")).click();
}
public void zCardDetails (String CardNumber) throws InterruptedException {
driver.findElement(By.name("creditnumber")).sendKeys(CardNumber);
}
public _05_BookAFlight zContinue () throws InterruptedException {
driver.findElement(By.name("buyFlights")).click();
Wait(3000);
return this;
}
}
9. _06_FlightConformation
package MercuryTours.PageObjects;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
public class _06_FlightConformation extends UtilityScript {
private WebDriver driver;
public _06_FlightConformation(WebDriver driver) throws InterruptedException {
this.driver = driver;
}
public void zGetConformationNumber () throws InterruptedException {
Print(driver.findElement(By.xpath("//tr/td/b/font/font/b/font[1]")).getText());
}
public _06_FlightConformation zLogOut () throws InterruptedException {
driver.findElement(By.xpath("//tbody/tr/td[3]/a")).click();
Print("---Logout---");
Wait(3000);
return this;
}
}
9. TestData.java
package MercuryTours.PageObjects;
public class TestData extends MercuryTours.TestNG.TestNGAssertionsCustom {
public static final String Url = "http://newtours.demoaut.com/";
public static final String UserName = "qtp123";
public static final String UserNameP = "qtp123";
//##################################################################################
// Don't change any thing below ####################################################
//##################################################################################
//Assigned variables****************************************************************
public static final int ImplicitWait = 5;
public static final int TimeOut10 = 10000;
public static final int TimeOut20 = 20000;
//Date Data*************************************************************************
//public static final String DateFormat = "dd.MM.yyyy_hh:mm a";
public static final String DateTimeFormat = "MM/dd/yyyy_hh:mm a";
//public static final String DateFormat = "dd.MM.yyyy";
public static final String DateFormat = "MM/dd/yyyy";
public static final String DateFormat1 = "MMM dd, yyyy";
//Non Assigned variables ***********************************************************
public static String NewDate, NewTime, Script, MethodName = "",Method="";
public static String Temp, Temp1,sMessages ="";
}
10. UtilityScript.java
There are lot of custom function written based on project requirement
package MercuryTours.PageObjects;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import java.awt.AWTException;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import javax.imageio.ImageIO;
import org.apache.commons.io.FileUtils;
import org.testng.Reporter;
public class UtilityScript extends TestData {
// Get date time
public java.lang.String xGetDateTime() throws Exception {
// get current date time with Date() to create unique file name
DateFormat dateFormat = new SimpleDateFormat("hh_mm_ssaadd_MMM_yyyy");
// get current date time with Date()
Date date = new Date();
return (dateFormat.format(date));
}
// DateFormat = "MMM dd, yyyy";
public java.lang.String xGetDate(String DateFormat) throws Exception {
// get current date time with Date() to create unique file name
DateFormat dateFormat = new SimpleDateFormat(DateFormat);
// get current date time with Date()
Date date = new Date();
return (dateFormat.format(date));
}
// Get date time with SelText
public java.lang.String xGetDateTimeSel() throws Exception {
// get current date time with Date() to create unique file name
DateFormat dateFormat = new SimpleDateFormat("hh_mm_ssaadd_MMM_yyyy");
// get current date time with Date()
Date date = new Date();
return ("S_" + dateFormat.format(date));
}
// Get date time with System IP
public java.lang.String xGetDateTimeIP() throws Exception {
// get current date time with Date() to create unique file name
DateFormat dateFormat = new SimpleDateFormat("hh_mm_ssaa_dd_MMM_yyyy");
// get current date time with Date()
Date date = new Date();
// To identify the system
InetAddress ownIP = InetAddress.getLocalHost();
return (dateFormat.format(date) + "_IP" + ownIP.getHostAddress());
}
public static void Wait(int MilliSec) throws InterruptedException {
Thread.sleep(MilliSec);
}
public void Print(String Text) {
System.out.println(Text);
Reporter.log(Text);
String Temp = Text;
sMessages = sMessages + Temp.replaceAll(" ", "_") + "#";
//System.out.println(Temp);
//System.out.println(sMessages);
}
public java.lang.String xAddMinutesToTheDateTime(String Date_TimeFormat,
int NumberOfMinutes) throws InterruptedException, ParseException {
SimpleDateFormat sdf = new SimpleDateFormat(DateTimeFormat);
Calendar c = Calendar.getInstance();
c.setTime(sdf.parse(Date_TimeFormat));
c.add(Calendar.MINUTE, NumberOfMinutes); // number of minutes
String str = sdf.format(c.getTime());
String delimiter = "_";
String[] temp;
temp = str.split(delimiter);
for (int i = 0; i < temp.length - 1; i++) {
NewDate = temp[i];
NewTime = temp[i + 1];
}
// Print(NewDate);
// Print(NewTime);
return (str); // dt is now the new date
}
public java.lang.String xAddDaysToTheDateTime(String CurrentDate,
int NumberOfDays, String DateFormat)
throws InterruptedException, ParseException {
SimpleDateFormat sdf = new SimpleDateFormat(DateFormat);
Calendar c = Calendar.getInstance();
c.setTime(sdf.parse(CurrentDate));
c.add(Calendar.DATE, NumberOfDays); // number of days
String str = sdf.format(c.getTime());
return (str); // dt is now the new date
}
public java.lang.String xGetCurrentDateEST(String DateFormat) throws Exception {
SimpleDateFormat dateFormat = new SimpleDateFormat(DateFormat);
dateFormat.setTimeZone(TimeZone.getTimeZone("EST5EDT"));
NewDate = dateFormat.format(new Date());
return (NewDate);
}
public java.lang.String xGetCurrentTimeEST() throws Exception {
SimpleDateFormat dateFormat = new SimpleDateFormat("hh:mm a");
dateFormat.setTimeZone(TimeZone.getTimeZone("EST5EDT"));
NewTime = dateFormat.format(new Date());
return (NewTime);
}
public void xKillIEs() throws Exception {
// I felt this is not closing the IEs effectively, so started relaying
// on VB script
Wait(3000);
/*
* final String KILL = "taskkill /IM "; String processName =
* "iexplore.exe"; // IE process Runtime.getRuntime().exec(KILL +
* processName);
*/
File directory = new File(".");
try {
Runtime.getRuntime().exec(
"wscript.exe " + directory.getCanonicalPath()
+ "\\KillIEs.vbs");
} catch (Exception e) {
e.printStackTrace();
}
Wait(5000); // Allow OS to kill the process
}
public boolean xFileExist(String FileNameWithPath) throws Exception {
java.io.File myDir = new java.io.File(FileNameWithPath);
if (myDir.exists()) {
Print("file exist");
return true;
} else {
Print("file does not exist");
assertTrue(false);
return false;
}
}
public void xMakeFileCopy(String NewFileNameWithPath,
String FileNameWithPath) throws Exception {
java.io.File base = new java.io.File(FileNameWithPath);
java.io.File newfile = new java.io.File(NewFileNameWithPath);
if (xFileExist(FileNameWithPath)) {
FileUtils.copyFile(base, newfile);
} else {
Print("file does not existcould not copy");
assertTrue(false);
}
if (xFileExist(NewFileNameWithPath)) {
Print("file copied sucessfully");
}
}
public void xDeleteFile(String FileNameWithPath) throws Exception {
java.io.File file = new java.io.File(FileNameWithPath);
if (xFileExist(FileNameWithPath)) {
FileUtils.deleteQuietly(file);
Print("File Deleted Successfully");
} else {
Print("file does not exist.Could not Delete");
// assertTrue(false);
}
}
public static void xScreenShot() {
try {
String NewFileNamePath;
java.awt.Dimension resolution = Toolkit.getDefaultToolkit()
.getScreenSize();
Rectangle rectangle = new Rectangle(resolution);
// Get the dir path
File directory = new File(".");
// System.out.println(directory.getCanonicalPath());
// get current date time with Date() to create unique file name
DateFormat dateFormat = new SimpleDateFormat(
"MMM_dd_yyyy__hh_mm_ssaa");
// get current date time with Date()
Date date = new Date();
// System.out.println(dateFormat.format(date));
// To identify the system
InetAddress ownIP = InetAddress.getLocalHost();
// System.out.println("IP of my system is := "+ownIP.getHostAddress());
NewFileNamePath = directory.getCanonicalPath() + "\\ScreenShots\\"
+ Method + "___" + dateFormat.format(date) + "_"
+ ownIP.getHostAddress() + ".png";
System.out.println(NewFileNamePath);
// Capture the screen shot of the area of the screen defined by the
// rectangle
Robot robot = new Robot();
BufferedImage bi = robot.createScreenCapture(new Rectangle(
rectangle));
ImageIO.write(bi, "png", new File(NewFileNamePath));
NewFileNamePath = "<a href=" + NewFileNamePath + ">ScreenShot"
+ "</a>";
// Place the reference in TestNG web report
Reporter.log(NewFileNamePath);
} catch (AWTException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void xUpdateTestDetails(String Status) throws Exception {
File directory = new File(".");
String Temp = Method + "_" + Status;
if (Method != ""){
try {
Runtime.getRuntime().exec(
"wscript.exe " + directory.getCanonicalPath()
+ "\\UpdateTestDetails.vbs "+ Temp + " " + sMessages);
Method = "";
sMessages = "";
} catch (Exception e) {
e.printStackTrace();
}
}
Wait(5000); // Allow OS to kill the process
}
}
MercuryTours.TestNg Package
package MercuryTours.TestNG;
import org.testng.IInvokedMethod;
import org.testng.IInvokedMethodListener;
import org.testng.ITestResult;
public class TestListenerAdapter implements IInvokedMethodListener {
public void afterInvocation(IInvokedMethod arg0, ITestResult arg1) {}
public void beforeInvocation(IInvokedMethod arg0, ITestResult arg1) {}
}
package MercuryTours.TestNG;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.testng.Assert;
import org.testng.ITestResult;
import org.testng.Reporter;
public class TestNGAssertionsCustom {
private static Map<ITestResult, List<Throwable>> verificationFailuresMap = new HashMap<ITestResult, List<Throwable>>();
public static void assertTrue(boolean condition) {
Assert.assertTrue(condition);
}
public static void assertTrue(boolean condition, String message) {
Assert.assertTrue(condition, message);
}
public static void assertFalse(boolean condition) {
Assert.assertFalse(condition);
}
public static void assertFalse(boolean condition, String message) {
Assert.assertFalse(condition, message);
}
public static void assertEquals(boolean actual, boolean expected) {
Assert.assertEquals(actual, expected);
}
public static void assertEquals(Object actual, Object expected) {
Assert.assertEquals(actual, expected);
}
public static void assertEquals(Object[] actual, Object[] expected) {
Assert.assertEquals(actual, expected);
}
public static void assertEquals(Object actual, Object expected, String message) {
Assert.assertEquals(actual, expected, message);
}
public static void verifyTrue(boolean condition) {
try {
assertTrue(condition);
} catch(Throwable e) {
addVerificationFailure(e);
}
}
public static void verifyTrue(boolean condition, String message) {
try {
assertTrue(condition, message);
} catch(Throwable e) {
addVerificationFailure(e);
}
}
public static void verifyFalse(boolean condition) {
try {
assertFalse(condition);
} catch(Throwable e) {
addVerificationFailure(e);
}
}
public static void verifyFalse(boolean condition, String message) {
try {
assertFalse(condition, message);
} catch(Throwable e) {
addVerificationFailure(e);
}
}
public static void verifyEquals(boolean actual, boolean expected) {
try {
assertEquals(actual, expected);
} catch(Throwable e) {
addVerificationFailure(e);
}
}
public static void verifyEquals(Object actual, Object expected) {
try {
assertEquals(actual, expected);
} catch(Throwable e) {
addVerificationFailure(e);
}
}
public static void verifyEquals(Object[] actual, Object[] expected) {
try {
assertEquals(actual, expected);
} catch(Throwable e) {
addVerificationFailure(e);
}
}
public static void fail(String message) {
Assert.fail(message);
}
public static List<Throwable> getVerificationFailures() {
List<Throwable> verificationFailures = verificationFailuresMap.get(Reporter.getCurrentTestResult());
return verificationFailures == null ? new ArrayList<Throwable>() : verificationFailures;
}
private static void addVerificationFailure(Throwable e) {
List<Throwable> verificationFailures = getVerificationFailures();
verificationFailuresMap.put(Reporter.getCurrentTestResult(), verificationFailures);
verificationFailures.add(e);
}
}
package MercuryTours.TestNG;
import org.testng.*;
import org.testng.TestListenerAdapter;
public class TestNGCustom extends TestListenerAdapter {
// Take screen shot only for failed test case
@Override
public void onTestFailure(ITestResult tr) {
try {
MercuryTours.PageObjects.UtilityScript.xScreenShot();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
MercuryTours.PageObjects.UtilityScript.xUpdateTestDetails("FAIL");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void onTestSkipped(ITestResult tr) {
// p2pZions.PageObjects.UtilityScript.xScreenShot();
try {
MercuryTours.PageObjects.UtilityScript.xUpdateTestDetails("SKIPPED");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void onTestSuccess(ITestResult tr) {
//p2pZions.PageObjects.UtilityScript.xScreenShot();
try {
MercuryTours.PageObjects.UtilityScript.xUpdateTestDetails("PASS");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
package MercuryTours.TestNG;
import java.util.List;
import org.testng.IInvokedMethod;
import org.testng.ITestResult;
import org.testng.Reporter;
import org.testng.internal.Utils;
public class TestNGCustomeListener extends TestListenerAdapter {
@Override
public void afterInvocation(IInvokedMethod method, ITestResult result) {
Reporter.setCurrentTestResult(result);
if (method.isTestMethod()) {
List<Throwable> verificationFailures = TestNGAssertionsCustom.getVerificationFailures();
//if there are verification failures...
if (verificationFailures.size() > 0) {
//set the test to failed
result.setStatus(ITestResult.FAILURE);
//if there is an assertion failure add it to verificationFailures
if (result.getThrowable() != null) {
verificationFailures.add(result.getThrowable());
}
int size = verificationFailures.size();
//if there's only one failure just set that
if (size == 1) {
result.setThrowable(verificationFailures.get(0));
} else {
//create a failure message with all failures and stack traces (except last failure)
StringBuffer failureMessage = new StringBuffer("Multiple failures (").append(size).append("):\n\n");
for (int i = 0; i < size-1; i++) {
failureMessage.append("Failure ").append(i+1).append(" of ").append(size).append(":\n");
Throwable t = verificationFailures.get(i);
String fullStackTrace = Utils.stackTrace(t, false)[1];
failureMessage.append(fullStackTrace).append("\n\n");
}
//final failure
Throwable last = verificationFailures.get(size-1);
failureMessage.append("Failure ").append(size).append(" of ").append(size).append(":\n");
failureMessage.append(last.toString());
//set merged throwable
Throwable merged = new Throwable(failureMessage.toString());
merged.setStackTrace(last.getStackTrace());
result.setThrowable(merged);
}
}
}
}
}
SeleniumWebdriver - Page objects Implementation - Part 2