The previous tutorial has explained the DataProviders in TestNG. The DataProvider in TestNG is a way to pass the parameters in the test functions. Using DataProvider in TestNG, we can easily inject multiple values into the same test case. It comes inbuilt into TestNG and is popularly used in data-driven frameworks.
It is an option for the parallel execution of tests in TestNG.
It is advisable to create 2 classes – one class contains the Test cases and another class defines TestNG parameters – DataProviders.
Let us create a class for the DataProvider method with all the Test Data as shown below:
import org.testng.annotations.DataProvider;
public class DataProviderDemo {
@DataProvider(name = "testData", parallel=true)
public Object[][] dataProvFunc() {
return new Object[][] {
{"","","Username cannot be empty"},
{"","Test","Username cannot be empty"},
{"$%1234","2345%$","Invalid credentials"}
};
}
}
An extra parameter “parallel” is required to initiate parallel execution in TestNG using the data provider.
Below is the test which uses the parameter from the data provider and runs the tests parallelly.
A new ThreadLocal is instantiated for each test class, since it’s in the BeforeClass annotation.
private static final ThreadLocal<WebDriver> WEB_DRIVER_THREAD_LOCAL = new ThreadLocal<WebDriver>();
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Suite" thread-count="2" data-provider-thread-count="2">
<test name="Test">
<classes>
<class name="DataProvider.DataProviderParallelTests"/>
</classes>
</test> <!-- Test -->
</suite> <!-- Suite -->
In this file, the data-provider-thread-count is set to 2, then two browsers will be opened, and the first two tests will run from the list.
Run the test script from testng.xml, Right-Click on the XML, and select Run As ->TestNG Suite.
The execution status shown below shows that 2 threads are active at a time, which execute 2 sets of data provider parameters – Thread 14 and Thread 15. Once the tests are finished for Thread 14 and Thread 15, they are closed and a new Thread 15 is again initiated to start the test execution of the 3rd parameter.
TestNG generates multiple test reports under the folder test-output. We are mainly concerned about 2 reports – emailable-report.html and index.html.
Emailable-report.html
Emailable reports are a type of summary report that one can transfer to other people in the team through any medium.
Index.html
Index report contains the index-like structure of different parts of the report, such as failed tests, test files, passed tests, etc. We can divide this report into two parts. The left part contains the index, and this is the reason it is called an index report, while the right part contains the explored content of that index.
We are done! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!
I have created an Excel – SearchInBing.xlsx and placed it on the Desktop. You can create a Test Data folder in your project and place the Excel file within it. So, my datasheet looks like the below:
Next, we will create a DataProvider method that will use another method to read the Excel file & create a 2D object from the row & column values of the Excel and return the same value, so that our test script can use it. The code for it would look like the below:
import org.apache.poi.ss.usermodel.Cell;
import org.testng.annotations.DataProvider;
import java.io.FileInputStream;
import java.io.IOException;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class ExcelDataProvider {
@DataProvider(name = "excelData")
public Object[][] excelDataProvider() throws IOException {
// We are creating an object from the excel sheet data by calling a method that
// reads data from the excel stored locally in our system
Object[][] arrObj = getExcelData(
C:\\Users\\Vibha\\Desktop\\SearchInBing.xlsx","Details");
return arrObj;
}
// This method handles the excel - opens it and reads the data from the
// respective cells using a for-loop & returns it in the form of a string array
public String[][] getExcelData(String fileName, String sheetName) throws IOException {
String[][] data = null;
try {
FileInputStream fis = new FileInputStream(fileName);
XSSFWorkbook workbook = new XSSFWorkbook(fis);
XSSFSheet sheet = workbook.getSheet(sheetName);
XSSFRow row = sheet.getRow(0);
int noOfRows = sheet.getPhysicalNumberOfRows();
int noOfCols = row.getLastCellNum();
Cell cell;
data = new String[noOfRows - 1][noOfCols];
for (int i = 1; i < noOfRows; i++) {
for (int j = 0; j < noOfCols; j++) {
row = sheet.getRow(i);
cell = row.getCell(j);
data[i - 1][j] = cell.getStringCellValue();
}
}
} catch (Exception e) {
System.out.println("The exception is: " + e.getMessage());
}
return data;
}
}
Now, create a class that contains the test code. By default, the data provider will be looked for in the current test class or one of its base classes. If you want to put your data provider in a different class, it needs to be a static method or a class with a no-arg constructor, and you specify the class where it can be found in the data provider class attribute.
Below is the sample project which uses Selenium and TestNG which is used to generate an Allure Report.
We have 2 pages. Below is the code for Login Page which contains all the web elements and methods related to that web elements.
LoginPage.java
public class LoginPage {
WebDriver driver;
By userName = By.name("txtUsername");
By password = By.name("txtPassword");
By titleText = By.id("logInPanelHeading");
By login = By.id("btnLogin");
By errorMessage = By.id("spanMessage");
public LoginPage(WebDriver driver) {
this.driver = driver;
}
// Set user name in textbox
public void setUserName(String strUserName) {
driver.findElement(userName).sendKeys(strUserName);
}
// Set password in password textbox
public void setPassword(String strPassword) {
driver.findElement(password).sendKeys(strPassword);
}
// Click on login button
public void clickLogin() {
driver.findElement(login).click();
}
@Step("Verify title of Login Page")
public void verifyPageTitle() {
String loginPageTitle = driver.findElement(titleText).getText();
Assert.assertTrue(loginPageTitle.contains("LOGIN Panel"));
}
/* Failed Test */
@Step("Verify error message when invalid credentail is provided")
public void verifyErrorMessage() {
String invalidCredentialErrorMessage = driver.findElement(errorMessage).getText();
Assert.assertTrue(invalidCredentialErrorMessage.contains("Incorrect Credentials"));
}
@Step("Enter username and password")
public void login(String strUserName, String strPasword) {
// Fill user name
this.setUserName(strUserName);
// Fill password
this.setPassword(strPasword);
// Click Login button
this.clickLogin();
}
}
Dashboard.java
public class DashboardPage {
WebDriver driver;
By dashboardPageTitle = By.id("welcome");
By options = By.cssSelector(
"#dashboard-quick-launch-panel-menu_holder > table > tbody > tr > td:nth-child(1) > div > a > span");
public DashboardPage(WebDriver driver) {
this.driver = driver;
}
@Step("Verify title of Dashboard page")
public void verifyDashboardPageTitle() {
String DashboardPageTitle = driver.findElement(dashboardPageTitle).getText();
Assert.assertTrue(DashboardPageTitle.contains("Welcome"));
}
@Step("Verify Quick Launch Options on Dashboard page")
public void verifyQuickLaunchOptions() {
String QuickLaunchOptions = driver.findElement(options).getText();
Assert.assertTrue(QuickLaunchOptions.contains("Assign Leave"));
}
}
Below are the Test classes for Login Page and Dashboard Page. Here, we have BaseTest Class also which contains the common methods needed by other test pages.
BaseTest.java
public class BaseTest {
public static WebDriver driver;
LoginPage objLogin;
DashboardPage objDashboardPage;
@Step("Start the application")
@BeforeMethod
public void setup() {
System.setProperty("webdriver.gecko.driver",
"C:\\Users\\Vibha\\Software\\geckodriver-v0.26.0-win64\\geckodriver.exe");
driver = new FirefoxDriver();
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("https://opensource-demo.orangehrmlive.com/");
}
@Step("Stop the application")
@AfterMethod
public void close() {
driver.close();
}
}
LoginTests.java
@Epic("Web Application Regression Testing")
@Feature("Login Page Tests")
@Listeners(TestExecutionListener.class)
public class LoginTests extends BaseTest {
LoginPage objLogin;
DashboardPage objDashboardPage;
@Severity(SeverityLevel.NORMAL)
@Test(priority = 0, description = "Verify Login Page")
@Description("Test Description : Verify the title of Login Page")
@Story("Title of Login Page")
public void verifyLoginPage() {
// Create Login Page object
objLogin = new LoginPage(driver);
// Verify login page text
objLogin.verifyPageTitle();
}
/* Failed Test */
@Severity(SeverityLevel.BLOCKER)
@Test(priority = 1, description = "Login with invalid username and password")
@Description("Test Description : Login Test with invalid credentials")
@Story("Unsuccessful Login to Application")
public void invalidCredentialTest() {
// Create Login Page object
objLogin = new LoginPage(driver);
objLogin.login("test", "test123");
// Verify login page text
objLogin.verifyErrorMessage();
}
}
We can order tests by severity by using @Severityannotation. Click here to know more about other Allure annotations.
DashboardTests.java
@Epic("Web Application Regression Testing")
@Feature("Dashboard Page Tests")
@Listeners(TestExecutionListener.class)
public class DashboardTests extends BaseTest {
LoginPage objLogin;
DashboardPage objDashboardPage;
@Severity(SeverityLevel.BLOCKER)
@Test(priority = 0, description = "Verify Dashboard Page")
@Description("Test Description : After successful login to application opens Dashboard page")
@Story("Successful login of application opens Dashboard Page")
public void DasboardTest() {
objLogin = new LoginPage(driver);
// login to application
objLogin.login("Admin", "admin123");
// go the dashboard page
objDashboardPage = new DashboardPage(driver);
// Verify dashboard page
objDashboardPage.verifyQuickLaunchOptions();
}
}
We can group tests with @Epic, @Feature, and @Stories annotations. Click here to know more about other Allure annotations.
TestExecutionListener.class
We can add attachments to our reports by using @Attachmentannotation. It can return String, byte [], etc. I need to add @Listeners({ TestExecutionListener.class }) declaration at the top of the test classes. Click here to know more about other Allure annotations.
public class TestExecutionListener implements ITestListener {
@Attachment(value = "Screenshot of {0}", type = "image/png")
public byte[] saveScreenshot(String name, WebDriver driver) {
return (byte[]) ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
}
@Override
public void onTestFailure(ITestResult result) {
saveScreenshot(result.getName(), BaseTest.driver);
}
}
Step 5 – Create testng.xml for the project
TestNG.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name = "Allure Reports">
<test name = "Login Page Tests">
<classes>
<class name = "com.example.TestNGAllureReportDemo.tests.LoginTests"/>
</classes>
</test>
<test name =" Dashboard Tests">
<classes>
<class name = "com.example.TestNGAllureReportDemo.tests.DashboardTests"/>
</classes>
</test>
</suite>
Step 6 – Run the Test and Generate Allure Report
To run the tests, use the below command
mvn clean test
In the below image, we can see that one test failed and two passed out of three tests.
To create an Allure Report, use the below command
allure serve
This will generate the beautiful Allure Test Report as shown below.
Allure Report Dashboard
The overview page hosts several default widgets representing the basic characteristics of your project and test environment.
Statistics – overall report statistics.
Launches – if this report represents several test launches, statistics per launch will be shown here.
Behaviors – information on results aggregated according to stories and features.
Executors – information on test executors that were used to run the tests.
History Trend – if tests accumulated some historical data, it’s a trend that will be calculated and shown on the graph.
Environment – information on the test environment.
Categories in Allure Report
The categories tab gives you a way to create custom defects classifications to apply for test results. There are two categories of defects – Product Defects (failed tests) and Test Defects (broken tests).
Suites in Allure Report
On the Suites tab a standard structural representation of executed tests, grouped by suites and classes can be found.
Graphs in Allure Report
Graphs allow you to see different statistics collected from the test data: status breakdown or severity and duration diagrams.
Timeline in Allure Report
The timeline tab visualizes retrospective of tests execution, allure adaptors collect precise timings of tests, and here on this tab, they are arranged accordingly to their sequential or parallel timing structure.
Behaviors of Allure Report
This tab groups test results according to Epic, Feature, and Story tags.
Packages in Allure Report
The packages tab represents a tree-like layout of test results, grouped by different packages.
If you click on the (highlighted tab), it will show the test execution report in the below format.
Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!! Cheers!!
There are 2 ways to run TestNG tests – using Run As TestNG tests and from testng.xml.
In this tutorial, I’m explaining how to create and run tests using TestNG.xml.
Step 1– In the below project, there is no testng.xml present.
Step 2 – Right click on class name “API_Test.java” and navigate “TestNG–>Convert to TestNG“.
Step 3– Now a new window for testng.xml will be generated as shown below. Click the Finish Button.
Below is the sample testng.xml.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Suite">
<test thread-count="5" name="Test">
<classes>
<class name="com.example.RestAssured_TestNG_Demo.API_Test"/>
</classes>
</test> <!-- Test -->
</suite> <!-- Suite -->
Step 4 – A xml file named “testng.xml“ will be generated in project hierarchy.
Step 5 – Right click on this testng.xml and select Run As–> Testng Suite.
Step 6 – You will view the result in two different tabs: Console and “Results of running suite”. Below is the image of Rest of running suite tab.
Multiple Classes
Let us imagine a scenario where there are 3 classes and we want to run them all together, you can done that by creating a testng.xml and mention all 3 classes in that testng.xml.
Select all 3 classes and right click and navigate “TestNG–>Convert to TestNG“.
This is how the testng.xml will look like for multiple classes.
Below is the sample testng.xml.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Suite">
<test thread-count="5" name="Test">
<classes>
<class name="com.example.RestAssured_TestNG_Demo.API_Test1"/>
<class name="com.example.RestAssured_TestNG_Demo.Test3"/>
<class name="com.example.RestAssured_TestNG_Demo.Test2"/>
</classes>
</test> <!-- Test -->
</suite> <!-- Suite -->
Right click on this testng.xml and select Run As–> Testng Suite. You will get the result in two tabs: Console and “Results of running suite”. This shows that all the tests present within the three classes are executed.
Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!! Cheers!!
Page Object Model(POM) is an object design pattern in Selenium webdriver which tells how to organize the object repository. In this case, we refer to web elements as Objects. Page Object Model(POM) is not a Test Framework.
In the Page Object Model (POM), each web page is represented as a separate class. For example, consider HRM website. It has many web pages like Login , Dashboard , Assign Leave, Leave List, Timesheets, etc. Under this model, for each web page in the application, there should be a corresponding Page Class. This Page class will identify the WebElements of that web page and also contains Page methods that perform operations on those WebElements.
If a new web element is added or an existing web element is updated, then you can add or update that web element in object repository by navigating to class which has same name as webpage.
The object repository is independent of test cases, so we can use the same object repository for a different purpose with different tools. For example, we can integrate Page Object Model in Selenium with TestNG/JUnit for functional Testing and at the same time with JBehave/Cucumber for acceptance testing.
POM enhances test maintenance, readability and reducing code duplication.
In this tutorial, I’m creating a project using Page Object Model as Design Pattern and TestNG as the Test Automation Framework.
Steps to create a Page Object Model Project
Download and Install Java on system
Download and setup Eclipse IDE on system
Setup Maven
Create a new Maven Project
Add dependencies to pom.xml
Create Page Class for each page – LoginPage.Java and DashboardPage.java
Create tests for each Page – BaseTests, LoginTests and DashboardTests
Create a TestNG.XML
Run the tests from TestNG.xml
TestNG Report Generation
Step 1- Download and Install Java
Click here to know How to install Java. To check if Java is already installed on your machine, use the below command in the command line. This command will show the version of Java installed on your machine.
java -version
Step 2 – Download and setup Eclipse IDE on system
The Eclipse IDE (integrated development environment) provides strong support for Java developer. The Eclipse IDE for Java Developers distribution is designed to support standard Java development. It includes support for the Maven and Gradle build system and support for the Git version control system. Click here to know How to install Eclipse.
Step 3 – Setup Maven
To build a test framework, we need to add a number of dependencies to the project. It is very tedious and cumbersome process to add each dependency manually. So, to overcome this problem, we use a build management tool. Maven is a build management tool which is used to define project structure, dependencies, build, and test management. Click here to know How to install Maven.
To know if Maven is already installed or not on your machine, type this command in the command line. This command will show the version of Maven installed on your machine.
Step 6 – Create Page Class for each page – LoginPage.Java and DashboardPage.java
I want to test 2 pages – Login and Dashboard. So, I’m creating 2 seperate class. Each class will contain its web elements and methods of that page.
LoginPage.Java
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
public class LoginPage {
WebDriver driver;
By userName = By.name("txtUsername");
By password = By.name("txtPassword");
By titleText = By.id("logInPanelHeading");
By login = By.id("btnLogin");
public LoginPage(WebDriver driver) {
this.driver = driver;
}
// Set user name in textbox
public void setUserName(String strUserName) {
driver.findElement(userName).sendKeys(strUserName);
}
// Set password in password textbox
public void setPassword(String strPassword) {
driver.findElement(password).sendKeys(strPassword);
}
// Click on login button
public void clickLogin() {
driver.findElement(login).click();
}
// Get the title of Login Page
public String getLoginTitle() {
return driver.findElement(titleText).getText();
}
public void login(String strUserName, String strPasword) {
// Fill user name
this.setUserName(strUserName);
// Fill password
this.setPassword(strPasword);
// Click Login button
this.clickLogin();
}
}
DashboardPage.java
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
public class DashboardPage {
WebDriver driver;
By homePageUserName = By.id("welcome");
public DashboardPage(WebDriver driver) {
this.driver = driver;
}
// Get the User name from Home Page
public String getHomePageText() {
return driver.findElement(homePageUserName).getText();
}
}
Step 7 – Create tests for each Page – BaseTests, LoginTests and DashboardTests
Here, I have created 3 classes. BaseTest class to contain startUp and tearDown methods. These methods will run once before the after of every class. LoginTests and DashboardTests classes contain the tests related to LoginPage and DashboardPage respectively.
BaseTest
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import com.example.pageobjectmodel_demo.pages.DashboardPage;
import com.example.pageobjectmodel_demo.pages.LoginPage;
public class BaseTest {
public static WebDriver driver;
LoginPage objLogin;
DashboardPage objDashboardPage;
@BeforeClass
public void setup() {
System.setProperty("webdriver.gecko.driver",
"C:\\Users\\Vibha\\Software\\geckodriver-v0.26.0-win64\\geckodriver.exe");
driver = new FirefoxDriver();
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("https://opensource-demo.orangehrmlive.com/");
}
@AfterClass
public void close() {
driver.close();
}
}
LoginTests
import org.testng.Assert;
import org.testng.annotations.Test;
import com.example.pageobjectmodel_demo.pages.DashboardPage;
import com.example.pageobjectmodel_demo.pages.LoginPage;
public class LoginTests extends BaseTest {
LoginPage objLogin;
DashboardPage objDashboardPage;
@Test(priority = 0)
public void loginTest() {
// Create Login Page object
objLogin = new LoginPage(driver);
// Verify login page text
String loginPageTitle = objLogin.getLoginTitle();
Assert.assertTrue(loginPageTitle.contains("LOGIN Panel"));
}
}
DashboardTests
import org.testng.Assert;
import org.testng.annotations.Test;
import com.example.pageobjectmodel_demo.pages.DashboardPage;
import com.example.pageobjectmodel_demo.pages.LoginPage;
public class DashboardTests extends BaseTest {
LoginPage objLogin;
DashboardPage objDashboardPage;
@Test(priority = 0)
public void DasboardTest() {
objLogin = new LoginPage(driver);
// login to application
objLogin.login("Admin", "admin123");
// go the dashboard page
objDashboardPage = new DashboardPage(driver);
// Verify dashboard page
Assert.assertTrue(objDashboardPage.getHomePageText().contains("Welcome"));
}
}
Step 8 – Create a TestNG.XML
Here, I have mentioned 2 test classes. So, when I will run the tests from TestNG.xml, it will run the tests of both the classes. If will mention any one class, then the test of that particular class will be executed.
<?xml version = "1.0"encoding = "UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name = "PageObjectModel">
<test name = "PageObjectModel Tests">
<classes>
<class name = "com.example.pageobjectmodel_demo.tests.LoginTests"/>
<class name = "com.example.pageobjectmodel_demo.tests.DashboardTests"/>
</classes>
</test>
</suite>
Step 9 – Run the tests from TestNG.xml
Right click on TestNG.xml and select Run As TestNG Suite.
The execution status looks like as shown below.
Step 10 – TestNG Report Generation
Once the execution is finished, refresh the project. It will create a test-output folder containing various reports generated by TestNG. Below is the screenshot of the report folder.
Image of Index.html report
Image of emailable-report.html
Cheers! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!
Page Object model is an object design pattern in Selenium, where web pages are represented as classes, and the various elements on the page are defined as variables in the class and all possible user interactions can then be implemented as methods in the class.
The benefit is that if there is any change in the UI for the page, the tests themselves don’t need to change, only the code within the page object needs to change. Subsequently all changes to support that new UI are located in one place.
Advantages:
1. Readable – There is a clean separation between test code and page specific code such as locators and methods.
2. Maintainability – In this model, separate classes are created for different pages of a web application like login page, the home page, employee detail page, change password page, etc. So, if there is any change in any element of a website then we only need to make changes in one class, and not in all classes.
3. Reusable – If multiple test scripts use the same web elements, then we need not write code to handle the web element in every test script. Placing it in a separate page class makes it reusable by making it accessible by any test script.
4. Easy project Structure– Its project structure is quite easy and understandable.
5. PageFactory – It can use PageFactory in the page object model in order to initialize the web element and store elements in the cache.
In case there are lots of web elements on a page, then the object repository class for a page can be separated from the class that includes methods for the corresponding page.
Example: If the New Customer page has many input fields. In that case, there can be 2 different classes. One class called NewCustomerObjects.java that forms the object repository for the UI elements on the register accounts page.
A separate class file NewCustomerMethods.java extending or inheriting NewCustomerObjects that includes all the methods performing different actions on the page could be created.
Consider the below script to login to an application and navigate to home page.
This is a small script. Therefore, script maintenance and readability looks very easy.
Imagine there are 50 different tests present in this script. In that case, the readability of the script decreases as well as maintenance become very difficult.
Scenario
Launch the Firefox browser.
The demo website opens in the browser.
Verify the Login Page
Enter username and Password and login to the demo site.
PageFactory is a way of implementing the “Page Object Model”. Here, we follow the principle of separation of Page Object Repository and Test Methods. It is an inbuilt concept of Page Object Model which is very optimized.
1. The annotation @FindBy is used in Pagefactory to identify an element while POM without Pagefactory uses the driver.findElement() method to locate an element.
2. The second statement for Pagefactory after @FindBy is assigning an <element name> of type WebElement class that works exactly similar to the assignment of an element name of type WebElement class as a return type of the method driver.findElement() that is used in usual POM (userName in this example).
3. Below is a code snippet of non PageFactory Mode to set Firefox driver path. A WebDriver instance is created with the name driver and the FirefoxDriver is assigned to the ‘driver’. The same driver object is then used to launch the demo website, locate the webelements and to perform various operations
Basically, here the driver instance is created initially and every web element is freshly initialized each time when there is a call to that web element using driver.findElement() or driver.findElements().
ChromeOptions options = new ChromeOptions();
driver = new ChromeDriver(options);
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("https://opensource-demo.orangehrmlive.com/");
But with POM with PageFactory approach, all the elements are initialized with initElements() without explicitly initializing each web element.
The initElementsis a static method of PageFactory class which is used to initialize all the web elements located by @FindBy annotation. Thus, instantiating the Page classes easily. It is used to initialize the WebElements declared, using driver instance from the main class. In other words, WebElements are created using the driver instance. Only after the WebElements are initialized, they can be used in the methods to perform actions.
public Login(WebDriver driver) {
this.driver = driver;
// This initElements method will create all WebElements
PageFactory.initElements(driver, this);
}
3.2 Create methods for actions performed on WebElements.
Below actions are performed on WebElements in Login Page:
Get Text on Login Page
Type action on the Username field.
Type action in the Password field.
Click action on the Login Button
Note: A constructor has to be created in each of the class in the Page Layer, in order to get the driver instance from the Main class in Test Layer and also to initialize WebElements(Page Objects) declared in the page class using PageFactory.InitElement().
BaseClass
package com.example.pages;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.PageFactory;
public class BasePage {
public WebDriver driver;
public BasePage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver,this);
}
}
Login Page
package com.example.pages;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
public class LoginPage extends BasePage{
public LoginPage(WebDriver driver) {
super(driver);
}
@FindBy(name = "username")
public WebElement userName;
@FindBy(name = "password")
public WebElement password;
@FindBy(xpath = "//*[@class='oxd-form']/div[3]/button")
public WebElement login;
@FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/div/div[1]/div[1]/p")
public WebElement errorMessage;
public void login(String strUserName, String strPassword) {
userName.sendKeys(strUserName);
password.sendKeys(strPassword);
login.click();
}
public String getErrorMessage() {
return errorMessage.getText();
}
}
HomePage. java
package com.example.pages;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
public class HomePage extends BasePage {
public HomePage(WebDriver driver) {
super(driver);
}
@FindBy(xpath = "//*[@id='app']/div[1]/div[1]/header/div[1]/div[1]/span/h6")
public WebElement homePageUserName;
public String getHomePageText() {
return homePageUserName.getText();
}
}
Step 4 – Create test class for the tests of these pages
BaseTests
package com.example.tests;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import java.time.Duration;
public class BaseTests {
public static WebDriver driver;
public final static int TIMEOUT = 10;
@BeforeMethod
public void setup() {
ChromeOptions options = new ChromeOptions();
options.addArguments("--remote-allow-origins=*");
options.addArguments("--no-sandbox");
options.addArguments("--disable-dev-shm-usage");
options.addArguments("--headless");
driver = new ChromeDriver(options);
driver.manage().window().maximize();
driver.get("https://opensource-demo.orangehrmlive.com/");
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(TIMEOUT));
}
@AfterMethod
public void tearDown() {
driver.quit();
}
}
LoginPageTests.java
package com.example.tests;
import com.example.pages.HomePage;
import com.example.pages.LoginPage;
import org.testng.Assert;
import org.testng.annotations.Test;
public class LoginPageTests extends BaseTests{
String actualResponse;
@Test
public void invalidCredentials() {
LoginPage objLoginPage = new LoginPage(driver);
objLoginPage.login("admin", "admin");
actualResponse = objLoginPage.getErrorMessage();
Assert.assertEquals(actualResponse,"Invalid credentials");
}
@Test
public void validCredentials() {
LoginPage objLoginPage = new LoginPage(driver);
objLoginPage.login("Admin", "admin123");
HomePage objHomePage = new HomePage(driver);
actualResponse = objHomePage.getHomePageText();
Assert.assertEquals(actualResponse,"Dashboard");
}
}
Step 5 – Execute the tests
To run the test, right click and select as Run As and then select TestNG Test (Eclipse).
Right-click on the LoginPageTests and select Run ‘LoginPageTests’ (IntelliJ)
Step 6 – Create TestNG.xml
You can add TestNG.xml and run the tests from there also.
<?xml version = "1.0"encoding = "UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name = "PageObjectModel">
<test name = "PageObjectModel Tests">
<classes>
<class name ="com.example.tests.LoginPageTests"/>
</classes>
</test>
</suite>
Step 7 – Run the tests from TestNG.xml
Right click on TestNG.xml and select Run As TestNG Suite.
The execution status looks like as shown below.
Step 8 -TestNG Report Generation
Once the execution is finished, refresh the project. It will create a test-output folder containing various reports generated by TestNG. Below is the screenshot of the report folder.
Index.html
emailable-report.html
Step 9 – Execute the tests through command line
We can run the tests through command line. Use the below command:
The listener is defined as an interface that modifies the default TestNG’s behaviour. There are several interfaces that allow you to modify TestNG’s behaviour that are called “TestNG Listeners”. It allows customizing TestNG reports or logs. There are many types of TestNG listeners available. Here are a few listeners:
IAnnotationTransformer
IAnnotationTransformer2
IHookable
IInvokedMethodListener
IMethodInterceptor
IReporter
ISuiteListener
ITestListener
When you implement one of these interfaces, you can let TestNG know about it in either of the following ways:
Using in yourtestng.xml file.
Using the@Listeners annotation on any of your test classes.
ITestListenerhas the following methods
OnStart – Invoked before running all the test methods belonging to the classes inside the tag and calling all their Configuration methods.
onTestSuccess – onTestSuccess method is called on the success of any Test.
onTestFailure – onTestFailure method is called on the failure of any Test.
onTestSkipped – onTestSkippedmethod is called on skipped of any Test.
onTestFailedButWithinSuccessPercentage– method is called each time Test fails but is within success percentage. Invoked each time a method fails but has been annotated with successPercentage and this failure still keeps it within the success percentage requested.
onFinish – Invoked after all the test methods belonging to the classes inside the tag have run and all their Configuration methods have been called.
onTestStart – Invoked each time before a test will be invoked. The ITestResult is only partially filled with the references to class, method, start millis, and status.
Here, I explain the use of listener – ITestListener in a program mentioned below
Step 1) Create a class “ListenerDemo” that implements ‘ITestListener’. Add methods like onTestFailure, onTestSkipped, onTestStart, onTestSuccessto this class
Step 2) Create another class “ListenerTestCases” for the login process automation. Selenium will execute these ‘TestCases’ to login automatically.
Step 3) Next, implement this listener in our regular project class i.e. “ListenerTestCases “. There are two different ways to connect to the class and interface.
The first way is to use Listeners annotation (@Listeners) as shown below:
Step 4): Execute the “ListenerTestCases” class. Methods in class “TestPass ” are called automatically according to the behaviour of methods annotated as @Test.
Step 5): Verify the Output that logs display at the console.
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;
public class ListenerDemo implements ITestListener {
// When Test case get failed, this method is called.
public void onTestFailure(ITestResult Result) {
System.out.println("The name of the testcase failed is :" + Result.getName());
}
// When Test case get Skipped, this method is called.
public void onTestSkipped(ITestResult Result) {
System.out.println("The name of the testcase Skipped is :" + Result.getName());
}
// When Test case get Started, this method is called.
public void onTestStart(ITestResult Result) {
System.out.println(Result.getName() + " test case started");
}
// When Test case get passed, this method is called.
public void onTestSuccess(ITestResult Result) {
System.out.println("The name of the testcase passed is :" + Result.getName());
}
}
In the below test, there are 2 test cases. One Test passes and another fails. When we are executing ListenerTestCases, it will call the ListenersDemo internally.
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
importorg.openqa.selenium.chrome.ChromeDriver;
import org.testng.Assert;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
@Listeners(com.selenium.testng.TestNGDemo.ListenerDemo.class)
public class ListenerTestCases {
static WebDriver driver;
@Test
public void TestPass() {
System.setProperty("webdriver.chrome.driver",
"C:\\Users\\Vibha\\Desktop\\SeleniumKT\\chromedriver_win32\\chromedriver.exe");
driver= new ChromeDriver();
driver.get("https://opensource-demo.orangehrmlive.com/");
driver.findElement(By.name("txtUsername")).sendKeys("Admin");
driver.findElement(By.name("txtPassword")).sendKeys("admin123");
driver.findElement(By.id("btnLogin")).submit();
String dashboardTitle = driver.findElement(By.id("welcome")).getText();
Assert.assertTrue(dashboardTitle.contains("Welcome"));
}
@Test
public void TestFail() {
System.setProperty("webdriver.chrome.driver",
"C:\\Users\\Vibha\\Desktop\\SeleniumKT\\chromedriver_win32\\chromedriver.exe");
driver= new ChromeDriver();
driver.get("https://opensource-demo.orangehrmlive.com/");
driver.findElement(By.name("txtUsername")).sendKeys("Admin");
driver.findElement(By.name("txtPassword")).sendKeys("admin123");
driver.findElement(By.id("btnLogin")).submit();
String dashboardTitle = driver.findElement(By.id("welcome")).getText();
Assert.assertTrue(dashboardTitle.contains("Hello"));
}
}
Output
TestFail test case started
The name of the testcase failed is :TestFail
TestPass test case started
The name of the testcase passed is :TestPass
PASSED: TestPass
FAILED: TestFail
java.lang.AssertionError: did not expect to find [true] but found [false]
The output of the above program is
To execute this program, we need to Right-click and select Run as – TestNG.
There is another way to execute the Listener class, which is using testng.xml. There is a Listener class named “ListenerDemo” where the implementation of various methods of the listener is present. If we want to run the tests using testng.xml, then there is no need of mentioning Listeners in the ListenerTestCases class.
<?xml version = "1.0"encoding = "UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name = "TestSuite">
<listeners>
<listener class-name ="com.selenium.testng.TestNGDemo.ListenerDemo"/>
</listeners>
<test name ="Test">
<classes>
<class name="com.selenium.testng.TestNGDemo.ListenerTestCases"/>
</classes>
</test>
</suite>
The test execution result will look like something shown below.
TestNG generates various types of reports under the test-output folder. Open “emailable-report.html”, as this is an HTML report open it with the browser. It will look like something below.
TestNG also produces an “index.html” report, and it resides under the test-output folder.
There is another example of Listener –ITestResult.
We are done! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!
Cross Browser is a technique in which a web application tests on different browsers and operating systems. Cross Browser testing, make sure that the site rendered the same in every browser.
Suppose, we have to execute 25 tests cases to test a web application on Google Chrome Browser and it takes around 4 hrs to execute these tests. However, we do not know if a user is going to access the web application on which browser. Therefore, now the same set of test cases need to executes on Firefox, Edge, Internet Explorer, Safari and Opera.
Therefore, now we need to execute 25*6=150 test cases and test execution hour changes from 4 to 24 hrs to check that the web application is working as expected. What is the best approach to handle this situation is to automate these tests and perform cross browser testing
Why do we need to perform cross browser testing?
Each website is built by anyone or combination of these technologies – HTML, CSS and Javascript. Each browser uses different rendering engines to compute these technologies. Chrome uses Blink, WebKit on iOS, V8 JavaScript engine, Firefox uses Gecko, Edge uses Chromium-based with Blink and V8 engines, Safari uses Webkit rendering engine, IE uses Trident and so on.
1) Font size, image orientation and alignment mismatch in different browsers
2) Different browser is compatible with different operating systems
3) CSS,HTML validation difference can be there
Lets see an example of Cross Browser testing using Selenium and TestNG.
Step 1 – Add the below dependencies to the POM.xml, in case of Maven project.
We need to specify the values of browser in the TestNG XML file that will pass to the test case file.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Suite" parallel="tests" thread-count="3">
<test name="Chrome Test">
<parameter name="browser" value="chrome" />
<classes>
<class name="com.example.crossbrowser.CrossBrowserTests"/>
</classes>
</test> <!-- Test -->
<test name="firefox Test">
<parameter name="browser" value="firefox" />
<classes>
<class name="com.example.crossbrowser.CrossBrowserTests"/>
</classes>
</test> <!-- Test -->
<test name="Edge Test">
<parameter name="browser" value="edge" />
<classes>
<class name="com.example.crossbrowser.CrossBrowserTests"/>
</classes>
</test> <!-- Test -->
</suite> <!-- Suite -->
To execute this program, we need to Right click on the program and select Run as – TestNGTest
The test execution result looks like as shown below. It shows the test execution status of all the tests. As, in this program, 3 tests are executed and all 3 of them passes. The same result can be depicted from below image.
TestNG Report Generation
TestNG generates various type of reports under test-output folder like emailable-report.html, index.html, testng-results.xml
We are interested in ’emailable-report.html’ report. Open ’emailable-report.html’, as this is a html report open it with browser. Below image shows emailable-report.html.
TestNG also produce “index.html” report and it resides under test-output folder. Below image shows index.html report.
We are done! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!
Assertions in TestNG are a way to verify that the expected result and the actual result matches or not in the test case. A test is considered successful ONLY if it is completed without throwing any exception. An example of assertion can be logging into the website, checking the title of the webpage, verifying the functionality of an input box that takes only integers, etc.
Below are few commonly used assertions in TestNG.
1. Assert.assertEquals(String actual, String expected) – It takes two string arguments and checks whether both strings are equal or not. If they are not, it will fail the test and an AssertionError is thrown.
2. Assert.assertEquals(String actual, String expected, String message)– It takes two string arguments and checks whether both strings are equal or not. If they are not, it will fail the test and an AssertionError is thrown with message provided as argument.
3. Assert.assertEquals(boolean actual, boolean expected)– It takes two Boolean arguments and checks whether both are equal or not. If they are not, it will fail the test and an AssertionError is thrown.
4. Assert.assertEquals(java.util.Collection actual, java.util.Collection expected, java.lang.String message) – It takes two collection objects and verifies both collections contain the same elements and with the same order. If they are not, it will fail the test and an AssertionError is thrown.
5. Assert.assertTrue(condition) – It takes one boolean argument and checks that a condition is true or not. If not, it will fail the test and an AssertionError is thrown.
6. Assert.assertTrue(condition, message) – It takes one boolean argument and checks that a condition is true or not. If not, it will fail the test and an AssertionError is thrown with message provided as argument.
7. Assert.assertFalse(condition)– It takes one boolean argument and checks that a condition is false or not. If not, it will fail the test and an AssertionError is thrown.
8. Assert.assertFalse(condition, message) – It takes one boolean argument and checks that a condition is false or not. If not, it will fail the test and an AssertionError is thrown with message provided as argument.
9. Assert.assertSame(String actual, String expected) – It asserts that two objects refer to the same object. If they do not, an AssertionError is thrown.
10. Assert.assertNotSame(String actual, String expected) – It asserts that two objects do not refer to the same object. If they do, an AssertionError is thrown.
package com.example;
import org.testng.Assert;
import org.testng.annotations.Test;
public class testAssertions {
@Test
public void testAssertions() {
// test data
String str1 = new String("TestNG");
String str2 = new String("TestNG");
String str3 = null;
String str4 = "TestNG";
String str5 = "TestNG";
String str6 = new String("Not_TestNG");
int val1 = 5;
int val2 = 6;
// Check that two objects are equal
Assert.assertEquals(str1, str2);
System.out.println("Equals Assertion is successful");
// Check that two objects are not equal
Assert.assertNotEquals(str1, str6);
System.out.println("NotEquals Assertion is successful");
// Check that a condition is true
Assert.assertTrue(val1 < val2);
System.out.println("True Assertion is successful");
// Check that a condition is false
Assert.assertFalse(val1 > val2);
System.out.println("False Assertion is successful");
// Check that an object isn't null
Assert.assertNotNull(str1);
System.out.println("Not Null Assertion is successful");
// Check that an object is null
Assert.assertNull(str3);
// Check if two object references point to the same object
Assert.assertSame(str4, str5);
System.out.println("Same Assertion is successful");
// Check if two object references not point to the same object
Assert.assertNotSame(str1, str3);
System.out.println("Not Same Assertion is successful");
}
}
The output of the above program is
Lets see if an assertion fails, how the output looks shown below. In the below example, we are verifying the pageTitle of Gmail. If the test fails, we should see the message provided in the assertion also.
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.testng.Assert;
import org.testng.annotations.Test;
public class TestNGAssertionFailureDemo {
@Test
public void AssertionFailure() throws InterruptedException {
FirefoxOptions options = new FirefoxOptions();
WebDriver driver = new FirefoxDriver(options);
// Test Condition 1: If Page title matches with actualTitle then it finds email
// title and enters the value which we pass
driver.get("https://www.gmail.com");
String actualTitle = "Google";
String expectedTitle = driver.getTitle();
Assert.assertEquals(expectedTitle, actualTitle, "Incorrect page title");
}
}
The output of the above program is
You can show in the output console, there is an error message “Incorrect page title” as we have mentioned this message in the Assertion.
In the previous tutorial, we have discussed How to Download and Install TestNG in Eclipse. In the this tutorial, we are going to discuss about the various annotations available in TestNG. Below is the list of annotations:-
@Test – This marks a class or a method as a part of the test.
@BeforeSuite – The @BeforeSuite method in TestNG runs before the execution of all other test methods. It will run only once before all tests in the suite have to run.
@AfterSuite – The @AfterSuite method in TestNG runs after the execution of all other test methods. It will run only once after all tests in the suite have run.
@BeforeTest – The @BeforeTest method in TestNG runs before the execution of first @Test method. It runs only once per class.
@AfterTest – The @AfterTest method in TestNG executes after the execution of all the test methods that are inside that folder.
@BeforeClass – The @BeforeClass method in TestNG will run before the first method invokes of the current class.
@AfterClass – The @AfterClass method in TestNG will execute after all the test methods of the current class execute.
@BeforeMethod – The @BeforeMethod method in TestNG will execute before each test method.
@AfterMethod – The @AfterMethod method in TestNG will run after each test method is executed.
@BeforeGroups – The @BeforeGroups method in TestNG run before the test cases of that group execute. It executes just once.
@AfterGroups– The @AfterGroups method in TestNG run after the test cases of that group execute. It executes only once.
@Parameters –This annotation is used to pass parameters to test methods.
@DataProvider– If we use @DataProvider annotation for any method that means you are using that method as a data supplier. The configuration of @DataProvider annotated method must be like it always return Object[][] which we can use in @Test annotated method. The @Test method that wants to receive data from this DataProvider needs to use a dataProvider name equals to the name of this annotation.
@Factory – Marks a method as a factory that returns objects that will be used by TestNG as Test classes. The method must return Object[ ].
@Listeners– This annotation is used with test class. It helps in writing logs and results.
Lets see a program to understand the sequence in which these annotations run in the program.
import org.testng.annotations.*;
public class AnnotationsExample {
@BeforeTest
public void init(){
System.out.println("---------------- Before Test ------------- ");
//open the browser
}
@AfterTest
public void quit(){
System.out.println("---------------- After Test ------------- ");
//close the browser
}
@BeforeMethod
public void beforeMethod() {
System.out.println("############# Before Method ############# ");
//Initialize the Report
}
@AfterMethod
public void afterMethod() {
System.out.println("############ After Method ##############");
//Finalize the Report
}
@BeforeClass
public void beforeClass() {
System.out.println("************* Before Class *************");
}
@AfterClass
public void afterClass() {
System.out.println("************* After Class ***************");
}
@BeforeSuite
public void beforeSuite() {
System.out.println("This will execute Before Suite");
}
@AfterSuite
public void afterSuite() {
System.out.println("This will execute After Suite");
}
@Test
public void loginTest(){
System.out.println("Login the application ");
}
@Test
public void logout(){
System.out.println("Logout the application ");
}
}
Execution process is as follows:
First of all, beforeSuite() method is executed only once.
2. Lastly, theafterSuite() method executes only once.
3. @BeforeMethod and @AfterMethod are executed twice, one for Test Case 1 and again for Test Case 2.
4. MethodsbeforeTest(), beforeClass(), afterClass(), and afterTest() methods are executed only once.
5. To execute this program, we need to Right click and select Run as -> TestNG or Run testng.xml.
The test execution result will look like something shown below
TestNG generates various type of reports under test-output folder.
Open ‘emailable-report.html‘, as this is a html report open it with browser. It will look like something below.
TestNG also produce “index.html” report and it resides under test-output folder.