TestNG is not the only option available in the market. But most of the automation testers prefer TestNG over other options like JUnit because TestNG allows parallel execution of test cases that saves loads of time possible with the help of the ‘parallel’ keyword in the XML file, TestNG’s seamless integration with tools like Jenkins, Maven, etc., and grouping of test cases also becomes easy with the use TestNG. These features have been instrumental in us providing the best software testing services to our clients. So in this TestNG tutorial, we will be focusing on how to make use of all these advantages and also explore all the advantages that TestNG brings to the table.
TestNG is an open-source testing framework where NG stands for Next Generation. It provides many features to execute the test methods by using various annotations like @Test @BeforeTest, @BeforeClass, etc. TestNG allows its users to generate robust test results that include the number of test cases that have Run, Passed, Failed, and Skipped. It can also be used to implement the logging feature using TestNG Listeners. On the whole, TestNG can also be used across various testing types like Unit, Regression, Functional, and API Testing. But before we get started with the TestNG Tutorial, let’s see how to set it up.
Installation and Setup of TestNG in IntelliJ:
IntelliJ requires a JAR file to add dependencies for TestNG script development and for running the test suites. So if it is a Maven Project, we would have to download the TestNG Jar File. Since we will be running tests on Java, we need to download an external TestNG Jar File onto our system by using the provided link.
Direct download link: TestNG/7.4.0/testng-7.4.0.jar
Reference: org.testng/TestNG
Please refer to the below image and instructions for a step-by-step guide,
i. Open IntelliJ,
ii. Create a new JAVA Project,
iii. Navigate to ‘File’ >> ‘Project Structure’ in IntelliJ,
iv. Click on ‘Libraries’ from Project Setting,
v. Add it to your ‘TestNG’ jar file, and then click on the ‘Apply and OK’ button.
If we want to work on a maven project, we have to mention the dependency in the POM.xml file
<dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>7.4.0</version> <scope>test</scope> </dependency>
TestNG Annotations:
TestNG annotations that are used to execute the test scripts can be defined by ‘@Test’ annotations. Before we head over to other aspects of the TestNG Tutorial, let’s take a look at the various annotations that are available in TestNG along with a short description of them.
Types of TestNG Annotations:
@Test Annotations:
We use this annotation to mark a method as a test method. The methods marked with @Test annotation are automatically invoked by the TestNG engine in default order (i.e.) alphabetically.
Syntax:
@Test public void TestMethod1() { System.out.println("\n Test-Method-001"); }
So in this part of the TestNG Tutorial, we will be focusing on the most important attributes of @Test annotations, starting with the description
1. ‘Description’ attribute of @Test Annotation:
The ‘Description’ keyword is used to provide a description of the test case. It can also be termed as a one-line summary, and it has been illustrated in the below example that describes the action of the user in a single line.
@Test(description = "User visits Codoid Home page") public void launchCodoidURL(){ System.out.println("\n >>> User visits Codoid Home page..."); }
2. Test Methods with Priority:
As mentioned earlier, we are aware that the methods will execute multiple test annotations alphabetically by default. But what if there is a need to run the methods or the test annotations based on defined priorities? Here is where the ‘Priority’ attribute comes into play, as it can be used to assign priorities to each test method. The highest priority would be given when a test method is marked with 1 and the priority decreases inversely as the number increases.
We have mentioned syntax below to denote how the priority attribute would function.
Syntax:
@Test(priority = 1) public void Test1() { System.out.println("\n Test-1"); } @Test(priority = 2) public void Test2() { System.out.println("\n Test-2"); }
3. Test Methods with Priority & without priority:
So in the above-mentioned syntax code, we saw 2 sets of programs that had defined priorities. But what if there is a need to define priorities only for a certain number of methods? It is very easy to accomplish as you can simply leave the methods that don’t need defined priorities and mark the other methods alone in the order that you wish. It is worth noting that the methods that had no defined priority will be run first on an alphabetical basis and then followed by the defined order.
Syntax:
@Test(priority = 1) //with Priority public void Test1() { System.out.println("\n Test-1"); } @Test //without priority public void TestMethod1() { System.out.println("\n Test-Method-001"); } @Test //without priority public void TestMethod2() { System.out.println("\n Test-Method-001"); } @Test(priority = 2) //with Priority public void Test2() { System.out.println("\n Test-2"); }
Code Explanation:
– Non-Prioritized methods ‘TestMethod1() and TestMethod2()’ have been executed in alphabetical order. (Line No: 60 and 65)
– Prioritized methods ‘Test1() and Test2()’ have been executed based on the priority level. (Line No: 55 and 69)
4. Depends On Methods in TestNG:
In our test scripts, we might have some methods that depend on the execution of another method before it is executed. For example, if a user wishes to send an email using the email application, then the user has to be logged in to the application first. So there will be no point in trying to send the mail if the sign-in is incomplete. So we can make use of this attribute that will help methods from getting executed if their dependent method doesn’t get a ‘Pass’. The same scenario is shown below as an example.
Syntax:
@Test public void UserLoginIntoEmailApplication(){ System.out.println("\n >> User Login :: "); } @Test(dependsOnMethods = "UserLoginIntoEmailApplication") public void UserSendAnNewEmail(){ System.out.println(">> User send an eMail"); }
Sometimes, there might be scenarios where a test case depends on more than one test method. So we can pass the parameters in annotations as shown below.
Syntax for dependsOnMethods: (Multiple Dependent Test methods)
@Test(dependsOnMethods = { "UserLoginIntoEmailApplication", "UserSendAnNewEmail" }) public void SignOut() { System.out.println(">>> Sign Out"); }
5. TestNG Groups:
The grouping concept is one of the best features of TestNG and one of the important parts of this TestNG Tutorial. So using this concept we can create a group of test methods based on modules/test cases. For example, the client requirement might demand you to execute a large number of smoke or regression tests. So you can simply pass the parameter in group attributes as shown below.
Syntax:
@Test(groups = { "Regression" }) public void userLogin() { .... } @Test(groups = { "Regression" }) public void userSendEmail() { .... }
So the groups are specified in the ‘.xml’ file and can either be used with the “groups” tag name or under the ‘test’ tag.
Syntax:
<groups> <run> <include name = "Regression"></include> </run> </groups>
DataProvider in TestNG:
In this method, a user will be able to pass the test data in test methods and also iterate the test methods using different data from the @DataProvider annotation, and it will return the 2D array objects.
Let’s see a simple example for this annotation,
Code:
@DataProvider(name = "data-provider") public Object[][] dataProviderMethod() { return new Object[][]{{"Codoid-001"}, {"Codoid-002"}}; } @Test(dataProvider = "data-provider") public void testDataProviderConcept(String strData) { System.out.println("\n >> Data: " + strData); }
Code Explanation:
We have maintained the array object and Test methods in the same class. In this method, the “testDataProviderConcept(String strData)” will iterate based on the array size. It will also retrieve the values “Codoid-001 and Codoid-002” from the ‘dataProviderMethod()’ with the help of the @DataProvider annotation.
Multiple Parameters in TestNG DataProvider:
It is even possible to pass multiple data through a single parameter. In this test method, we will be able to retrieve the data using multiple arguments as shown in the example,
For example,
@DataProvider(name = "data-provider") public Object[][] dataProviderMethod(){ return new Object[][] {{123,456 ,789}, {001, 002, 003}}; } @Test(dataProvider = "data-provider") public void testMethod(int value1, int value2, int value3) { System.out.println("\n >> value1: "+value1+"; Value2: "+value2+"; Value3: "+value3); }
DataProvider In TestNG Using Inheritance concept:
If you are looking for a way to maintain the code based on the project structure, then the DataProvider methods can maintain one class and the test methods can maintain another class. Let’s take a look at the example to find out how.
For example, we can access the dataprovider class using another attribute like “dataProviderClass”
Syntax :
@Test(dataProvider = “data-provider”, dataProviderClass = DP.class)
Note:
i. dataProviderClass // attribute Name
ii. DP.class // class Name; To inherit the other class.
Code:
//Class-1 @Test(dataProvider = "data-provider", dataProviderClass = DataProviderUtil.class) public void testDataProviderConcept(String strData) { System.out.println("\n >> Data: " + strData); } //Class-2 "Class Name: DataProviderUtil" @DataProvider(name = "data-provider") public Object[][] dataProviderMethod() { return new Object[][]{{"Codoid-001"}, {"Codoid-002"}};
TestNG Tutorial for using Excel Workbook as a Data Provider:
Now that we have seen how to pass the parameter with single or multiple data through an array object, but what if there is a need that demands a large number of data be used? Adding everything to the code will not be an optimal choice at all. We have a solution to overcome this in our TestNG Tutorial and so let’s focus on how we can retrieve data from an Excel workbook. Knowing this will come in very handy while executing Functional tests, and when there is a need to create a large amount of test data for performing Load tests.
We are going to implement the Excel workbook in the TestNG-DataProvider annotation to fetch the data from the excel sheet and search the products in Amazon. In the example, we have listed a few mobile phones like iPhone 12, Pixel 4a, and so on in the excel sheet.
The below-mentioned Excel util class is used to retrieve the data from the Excel sheet.
ExcelUtil.JAVA
Code:
/*Description: We can retrieve the data from the Excel workbook * parameter-1: Excel workbook directory path, * parameter-2: Sheet name*/ public static Iterator<Object[]> getTestData(String strWorkbookPath, String strWorksheetName) { List<Object[]> data = new ArrayList<Object[]>(); int inRowCounter = 0; try { FileInputStream file = new FileInputStream(new File(strWorkbookPath)); //Get the workbook instance for the xlsx file. HSSFWorkbook workbook = new HSSFWorkbook(file); //Get the first sheet from the workbook HSSFSheet sheet = workbook.getSheet(strWorksheetName); //Get an iterator to all the rows in the current sheet Iterator<Row> rowIterator = sheet.rowIterator(); Row firstRow = rowIterator.next(); Map<String, String> columnNamesMap = getColumnNames(firstRow); while (rowIterator.hasNext()) { Iterator<Cell> cellIterator = rowIterator.next().cellIterator(); Map<String, String> rowMap = new LinkedHashMap(); for (Entry entry : columnNamesMap.entrySet()) { String strColumnName = entry.getKey().toString(); String strValue = cellIterator.next().toString(); rowMap.put(strColumnName, strValue); } } file.close(); } catch (Exception e) { e.printStackTrace(); } return data.iterator(); } private static Map<String, String> getColumnNames(Row row) { Map<String, String> columnNamesMap = new LinkedHashMap(); Iterator<Cell> cells = row.cellIterator(); while (cells.hasNext()) { String strColumnName = cells.next().toString(); columnNamesMap.put(strColumnName, strColumnName); } return columnNamesMap; }
DataProvider.Class
@DataProvider(name = "AmazonProduct", parallel = false) public static Iterator<Object[]> getDeviceName() { String strWorkBookPath = new StringBuilder().append(System.getProperty("user.dir")).append(File.separator) .append("resources\\testdata").append(File.separator).append("testdata").append(".xlsx").toString(); Iterator<Object[]> testData = ExcelUtil.getTestData(strWorkBookPath, "Mobiles"); return testData; }
TestScripts.java
@Test(dataProvider = "AmazonProduct", dataProviderClass = DataProviderUtil.staticProviderClass.class) public void searchAmazonProducts(Map<String, String> dataMap) { System.setProperty("webdriver.chrome.driver", "./resources/drivers/chromedriver.exe"); driver = new ChromeDriver(); driver.get("https://www.amazon.in/"); wait = new WebDriverWait(driver, 25); WebElement txtSearchEngine = wait.until(ExpectedConditions.visibilityOfElementLocated( By.cssSelector("#twotabsearchtextbox"))); System.out.println("\n Devices : " + dataMap.get("Devices")); txtSearchEngine.sendKeys(dataMap.get("Devices")); txtSearchEngine.submit(); driver.quit(); }
Please refer to the below image,
Parameterization in TestNG:
When there is a need to perform tests by using different test data, or when you are looking to test by logging in with a different user that has distinct usernames and passwords then Parameterization will come in handy as the “@Parameters” annotation in TestNG allows argument values to pass to Test methods via the testng.xml file. (Parameter values are declared in testng.xml) We have explained the different user scenarios using an example.
Syntax:
@Parameters({ “param-name” })
Let’s write a simple program for the @Parameters annotation,
Code:
@Test @Parameters({"Username"}) public void TestMethod1(String strUsername) { //We can retrieve the data using this argument. (It’ll retrieve from testng.xml file) System.out.println("\n Username : " + strUsername); }
TestNG Tutorial for Parallel Execution:
Saving time during the testing process is always a priority, and one of the best possible ways to do it would be by executing tests in parallel rather than sequential execution. So as promised at the beginning of this TestNG Tutorial, let’s see how we can have test suites executed in parallel on different browsers, and how it can be even defined in the Testing.xml file.
TestNG provides different levels of execution that we can achieve by using the Testing.xml file. The attributes that we can use to achieve them are,
i. Methods,
ii. Classes, and
iii. Tests.
i. parallel=”methods”:
We had already seen about methods that are dependent on other methods for their execution, so accordingly if you are looking to execute many independent methods in parallel, then this attribute can be used. Using this attribute, all test methods will run on a separate thread. In the below example, we have executed two test methods in two threads.
Note: Thread count is the specified number of browser instances that should be assigned for this test execution.
Syntax:
<suite name="Test-method Suite" parallel="methods" thread-count="2" >
Code :
TestParallelForMethodsExecution.java
public class TestParallelForMethodsExecution { @Test public void visitCodoidPage() { String baseUrl = "https://codoid.com/"; System.setProperty("webdriver.chrome.driver", "./resources/drivers/chromedriver.exe"); WebDriver driver = new ChromeDriver(); driver.get(baseUrl); driver.manage().window().maximize(); WebDriverWait wait = new WebDriverWait(driver, 25); String testTitle = "QA Testing Company - Software Testing Services"; boolean isVerified = wait.until(ExpectedConditions.titleContains(testTitle)); Assert.assertTrue(isVerified); WebElement elmntAboutUsTab = driver.findElement(By.xpath("//ul[@id='top-menu']/li/a[text()='About Us']")); elmntAboutUsTab.click(); driver.close(); } @Test public void visitAmazonPage() { String baseUrl = "https://www.amazon.in/"; System.setProperty("webdriver.chrome.driver", "./resources/drivers/chromedriver.exe"); WebDriver driver = new ChromeDriver(); driver.get(baseUrl); driver.manage().window().maximize(); WebDriverWait wait = new WebDriverWait(driver, 25); String testTitle = "Online Shopping site in India"; boolean isVerified; isVerified = wait.until(ExpectedConditions.titleContains(testTitle)); Assert.assertTrue(isVerified); driver.close(); } }
TestNG.xml
<suite thread-count="2" name="Parallel-Test-Suite" parallel="methods"> <test name="To Run TestNG :: Parallel methods concept"> <classes> <class name="scripts.TestParallelForMethodsExecution"/> </classes> </test> </suite>
ii. parallel=”tests”:
But the problem is that the above type will not work if we have a lot of test methods that are dependent on each other like how we saw earlier with the email example. So this attribute can be used to overcome this issue by adding all the dependent tests to a suite file (Testing.xml) and executing it separately in a thread as each
Syntax:
<suite name="Test-Suite" parallel="tests" thread-count="2">
Code
MultipleSession1.java
public class MultipleSession1 { public static WebDriver driver = null; public static WebDriverWait wait = null; @Test public void visitAmazonPage() { String baseUrl = "https://www.amazon.in/"; System.setProperty("webdriver.chrome.driver", "./resources/drivers/chromedriver.exe"); driver = new ChromeDriver(); driver.get(baseUrl); driver.manage().window().maximize(); wait = new WebDriverWait(driver, 25); String testTitle = "Online Shopping site in India"; boolean isVerified; isVerified = wait.until(ExpectedConditions.titleContains(testTitle)); Assert.assertTrue(isVerified); } @BeforeMethod public void beforeMethod() { System.out.println("\n Starting Test On Chrome Browser"); } @AfterTest public void terminateBrowser() { driver.close(); } }
MultipleSession2.java
public class MultipleSession2 { public static WebDriver driver = null; public static WebDriverWait wait = null; @Test public void visitCodoidAboutUsPage() { String baseUrl = "https://codoid.com/"; System.setProperty("webdriver.chrome.driver", "./resources/drivers/chromedriver.exe"); driver = new ChromeDriver(); driver.get(baseUrl); driver.manage().window().maximize(); wait = new WebDriverWait(driver, 25); String testTitle = "QA Testing Company - Software Testing Services"; boolean isVerified = wait.until(ExpectedConditions.titleContains(testTitle)); Assert.assertTrue(isVerified); WebElement elmntAboutUsTab = driver.findElement(By.xpath("//ul[@id='top-menu']/li/a[text()='About Us']")); elmntAboutUsTab.click(); } @BeforeMethod public void beforeMethod() { System.out.println("\n Starting Test On Chrome Browser"); } @AfterTest public void terminateBrowser() { driver.close(); } }
TestNG.xml
<suite thread-count="2" name="Parallel-Test-Suite" parallel="tests"> <test name="To Run TestNG :: Parallel Tests concept - 1"> <classes> <class name="scripts.MultipleSession1"/> </classes> </test> <test name="To Run TestNG :: Parallel Tests concept - 2"> <classes> <class name="scripts.MultipleSession2"/> </classes> </test> </suite>
iii. parallel=”classes”:
This type has similar usage scope as the previous one with one major difference. Using this attribute, we can execute tests under each class in an individual thread, and the same has been explained in the below example.
Syntax:
<suite thread-count=”2” name =”Parallel-Test-Suite” parallel=”classes”>
Code:
Test1.java
public class Test1 { public static WebDriver driver = null; public static WebDriverWait wait = null; @Test public void Test1() { String baseUrl = "https://codoid.com/"; System.setProperty("webdriver.chrome.driver", "./resources/drivers/chromedriver.exe"); driver = new ChromeDriver(); driver.get(baseUrl); driver.manage().window().maximize(); wait = new WebDriverWait(driver, 25); } @Test public void Test2() { String testTitle = "QA Testing Company - Software Testing Services"; boolean isVerified; isVerified = wait.until(ExpectedConditions.titleContains(testTitle)); Assert.assertTrue(isVerified); } @Test public void Test3() throws InterruptedException { WebElement elmntAboutUsTab = driver.findElement(By.xpath("//ul[@id='top-menu']/li/a[text()='About Us']")); elmntAboutUsTab.click(); } @AfterTest public void terminateBrowser() { driver.close(); } }
Test2.java
public class Test2 { public static WebDriver driver = null; public static WebDriverWait wait = null; @Test(priority = 1) public void launchAmazonURL() { String baseUrl = "https://www.amazon.in/"; System.setProperty("webdriver.chrome.driver", "./resources/drivers/chromedriver.exe"); driver = new ChromeDriver(); driver.get(baseUrl); driver.manage().window().maximize(); wait = new WebDriverWait(driver, 25); } @Test(priority = 2) public void verifyAmazonTitle() { String testTitle = "Online Shopping site in India"; boolean isVerified; isVerified = wait.until(ExpectedConditions.titleContains(testTitle)); Assert.assertTrue(isVerified); } @Test(priority = 3) public void navigatesToAboutUsPage() throws InterruptedException { WebElement elmntAmazonPayTab = driver.findElement(By.xpath("//a[text()='Amazon Pay']")); elmntAmazonPayTab.click(); } @BeforeMethod public void beforeMethod() { System.out.println("\n Starting Test On Chrome Browser"); } @AfterTest public void terminateBrowser() { driver.close(); } }
TestNG.xml
<suite thread-count="2" name="Parallel-Test-Suite" parallel="classes"> <test name="Using Classes attributes for parallel execution."> <classes> <class name="scripts.Test1"/> <class name="scripts.Test2"/> </classes> </test> </suite>
In the above 3 points, it can be seen that we have defined the keywords for parallel (classes, tests, and methods) attributes on the Testing.xml file. Now, we’re going to explain the sample scripts for classes and methods.
Conclusion:
As promised at the beginning of this TestNG tutorial, we have explored all the plus points of TestNG. So we hope this information would be useful and that you have enjoyed reading this blog. As one of the leading automation testing companies, we have always found TestNG beneficial in crucial circumstances, and hope it will come in handy for you as well.
Comments(0)