Youโre at the right place if youโre looking forward to Refresh and Relearn TestNG in the fastest possible way.
Whether youโre a seasoned SDET or new to test automation, this refresher will help you master TestNG. You will become a TestNG sorcerer. TestNG is more than a testing framework; itโs our magical toolkit for crafting powerful, efficient, and elegant tests. Ready to go?
๐ Got a better free video course than the one above?ย Share the link in the commentsย for it to be considered to replace the video above!
Why TestNG is the Gandalf of Testing Frameworks?
TestNG (Test Next Generation) is a Java-based testing framework that puts you in control of your test execution. Its key strengths include:
- Rich Annotations: Simplifies test case setup and teardown.
- Data-Driven Testing: Handles test data like a pro.
- Parallel Execution: Speeds up testing by running multiple tests simultaneously.
- Seamless Integration: Works like a charm with Selenium, CI/CD tools, and reporting libraries.
Letโs explore its magic with real-world examples and executable code. ๐
Mastering TestNG Annotations ๐จ
TestNG annotations are the spells that make your test scripts manageable and powerful. Hereโs a quick overview:
Annotation | Purpose | Example |
---|---|---|
@Test | Marks a method as a test method. | @Test public void searchTest() {} |
@BeforeSuite | Runs before all tests in the suite. | @BeforeSuite public void initializeSuite() {} |
@AfterSuite | Runs after all tests in the suite. | @AfterSuite public void cleanupSuite() {} |
@BeforeTest | Executes before <test> in the XML. | @BeforeTest public void setupTests() {} |
@AfterTest | Executes after <test> in the XML. | @AfterTest public void cleanupTests() {} |
@BeforeClass | Runs before the first test in the current class. | @BeforeClass public void setupClass() {} |
@AfterClass | Runs after all tests in the current class. | @AfterClass public void cleanupClass() {} |
@BeforeMethod | Runs before each test method. | @BeforeMethod public void setupMethod() {} |
@AfterMethod | Runs after each test method. | @AfterMethod public void cleanupMethod() {} |
@DataProvider | Supplies test data for methods. | @DataProvider(name = "data") public Object[][] testData() {} |
@Parameters | Injects parameters from the XML file. | @Parameters({ "browser" }) public void setup(String browser) {} |
@Listeners | Adds listeners for custom reporting or actions during execution. | @Listeners(CustomListener.class) |
@Factory | Dynamically creates instances of test classes. | @Factory public Object[] createInstances() {} |
A Practical Example ๐น๏ธ
Hereโs a full example of a TestNG test suite that searches Google, clicks the fourth result, and closes the browser.
1. TestSetup.java
package tests; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.testng.annotations.*; public class TestSetup { protected WebDriver driver; @BeforeSuite public void beforeSuite() { System.out.println("Initializing Test Suite..."); } @BeforeClass public void beforeClass() { System.out.println("Setting up before class..."); } @Parameters("browser") @BeforeMethod public void setUp(@Optional("chrome") String browser) { System.setProperty("webdriver.chrome.driver", "path/to/chromedriver"); driver = new ChromeDriver(); driver.manage().window().maximize(); } @AfterMethod public void tearDown() { if (driver != null) { driver.quit(); } } @AfterClass public void afterClass() { System.out.println("Cleaning up after class..."); } @AfterSuite public void afterSuite() { System.out.println("Test Suite Execution Complete."); } }
2. GoogleSearchTest.java
package tests; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.util.List; public class GoogleSearchTest extends TestSetup { @Test(dataProvider = "searchTerms") public void googleSearch(String searchTerm) { driver.get("https://www.google.com"); driver.findElement(By.name("q")).sendKeys(searchTerm); driver.findElement(By.name("btnK")).click(); List<WebElement> results = driver.findElements(By.cssSelector(".LC20lb")); Assert.assertTrue(results.size() >= 4, "Less than 4 results found!"); results.get(3).click(); System.out.println("Clicked the fourth result for: " + searchTerm); } @DataProvider(name = "searchTerms") public Object[][] searchData() { return new Object[][] { {"TestNG"}, {"Selenium"}, {"Java Programming"} }; } }
3. testng.xml
<suite name="GoogleSearchSuite"> <test name="GoogleSearchTests"> <parameter name="browser" value="chrome"/> <classes> <class name="tests.GoogleSearchTest"/> </classes> </test> </suite>
Advanced Features in TestNG ๐ฌ
1. Parallel Test Execution
Boost execution speed with parallel tests.
<suite name="ParallelSuite" parallel="methods" thread-count="3"> <test name="ParallelTest"> <classes> <class name="tests.GoogleSearchTest"/> </classes> </test> </suite>
2. Retry Logic for Flaky Tests
package utils; import org.testng.IRetryAnalyzer; import org.testng.ITestResult; public class RetryAnalyzer implements IRetryAnalyzer { private int retryCount = 0; private static final int maxRetryCount = 2; @Override public boolean retry(ITestResult result) { if (retryCount < maxRetryCount) { retryCount++; return true; } return false; } }
@Test(retryAnalyzer = utils.RetryAnalyzer.class) public void flakyTest() { Assert.fail("Simulating a flaky test."); }
3. Test Grouping
@Test(groups = {"smoke"}) public void smokeTest() { System.out.println("Running smoke test..."); } @Test(groups = {"regression"}) public void regressionTest() { System.out.println("Running regression test..."); }
Another example, that incorporates all the TestNG annotations in a cohesive, practical scenario. This example demonstrates a test script for interacting with a search engine (Google). It performs various checks, such as parameterized and data-driven testing. It also includes listeners and grouping.
Project Directory Structure
Example/
โโโ src/main/java/
โโโ src/test/java/
โ โโโ config/
โ โ โโโ TestSetup.java
โ โโโ listeners/
โ โ โโโ CustomListener.java
โ โโโ tests/
โ โ โโโ GoogleSearchTest.java
โ โโโ testng.xml
TestSetup.java
(Reusable Configuration)
package config;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.*;
public class TestSetup {
protected WebDriver driver;
@BeforeSuite
public void beforeSuite() {
System.out.println("๐ง Initializing suite-wide setup...");
}
@AfterSuite
public void afterSuite() {
System.out.println("๐ง Cleaning up after suite...");
}
@BeforeTest
public void beforeTest() {
System.out.println("๐ง Setting up before test...");
}
@AfterTest
public void afterTest() {
System.out.println("๐ง Tearing down after test...");
}
@BeforeClass
public void beforeClass() {
System.out.println("๐ง Setting up before the class...");
}
@AfterClass
public void afterClass() {
System.out.println("๐ง Cleaning up after the class...");
}
@BeforeMethod
@Parameters("browser")
public void setUp(@Optional("chrome") String browser) {
System.out.println("๐ง Launching browser: " + browser);
driver = new ChromeDriver();
driver.manage().window().maximize();
}
@AfterMethod
public void tearDown() {
System.out.println("๐ง Closing browser...");
if (driver != null) {
driver.quit();
}
}
}
GoogleSearchTest.java
(Test Implementation)
package tests;
import config.TestSetup;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.testng.Assert;
import org.testng.annotations.*;
public class GoogleSearchTest extends TestSetup {
@DataProvider(name = "searchTerms")
public Object[][] provideSearchTerms() {
return new Object[][] {
{"Selenium WebDriver"},
{"TestNG Annotations"},
{"Java Tutorial"}
};
}
@Test(groups = {"smoke", "search"}, priority = 1)
public void openGoogle() {
driver.get("https://www.google.com");
String title = driver.getTitle();
System.out.println("Page title: " + title);
Assert.assertTrue(title.contains("Google"), "Google page did not load!");
}
@Test(dataProvider = "searchTerms", groups = {"functional", "search"}, priority = 2)
public void performSearch(String searchTerm) {
driver.get("https://www.google.com");
driver.findElement(By.name("q")).sendKeys(searchTerm + Keys.ENTER);
System.out.println("Searched for: " + searchTerm);
Assert.assertTrue(driver.getTitle().contains(searchTerm), "Search results not loaded!");
}
@Test(dependsOnMethods = {"performSearch"}, groups = {"functional", "search"}, priority = 3)
public void clickFourthResult() {
driver.findElement(By.cssSelector("h3")).click();
System.out.println("Clicked on the fourth result.");
}
@Test(threadPoolSize = 2, invocationCount = 2, groups = {"performance"}, priority = 4)
public void loadPerformanceTest() {
driver.get("https://www.google.com");
System.out.println("Loaded Google for performance test!");
}
}
CustomListener.java
(Listener Example)
package listeners;
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;
public class CustomListener implements ITestListener {
@Override
public void onTestStart(ITestResult result) {
System.out.println("๐ Starting test: " + result.getName());
}
@Override
public void onTestSuccess(ITestResult result) {
System.out.println("โ
Test passed: " + result.getName());
}
@Override
public void onTestFailure(ITestResult result) {
System.out.println("โ Test failed: " + result.getName());
}
@Override
public void onTestSkipped(ITestResult result) {
System.out.println("โ Test skipped: " + result.getName());
}
@Override
public void onStart(ITestContext context) {
System.out.println("๐ Starting suite: " + context.getName());
}
@Override
public void onFinish(ITestContext context) {
System.out.println("๐ Finished suite: " + context.getName());
}
}
testng.xml
(Execution Configuration)
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="TestNG Suite" parallel="tests" thread-count="2">
<listeners>
<listener class-name="listeners.CustomListener"/>
</listeners>
<test name="Google Search Tests">
<parameter name="browser" value="chrome"/>
<classes>
<class name="tests.GoogleSearchTest"/>
</classes>
</test>
</suite>
Features Covered
- Annotations:
- Setup/Teardown:
@BeforeSuite
,@AfterSuite
, etc. - Test Execution:
@Test
,@DataProvider
,@Parameters
.
- Setup/Teardown:
- Grouping:
@Test(groups = {"smoke", "functional"})
. - Dependency Testing:
@Test(dependsOnMethods = ...)
. - Parallel Execution:
parallel="tests"
intestng.xml
. - Listeners: Implemented a custom listener to handle events.
- Threading: Used
threadPoolSize
andinvocationCount
.
Next Steps
Add this project to your GitHub repo. Let me know if you’d like further enhancements. These may include reporting with ExtentReports or Allure.
FAQs
1. What makes TestNG better than JUnit?
- Flexible annotations, better dependency handling, and native support for parallel execution.
2. Can I integrate TestNG with Selenium?
- Absolutely! TestNG and Selenium are a match made in testing heaven.
3. What is the use of @DataProvider
?
- Itโs used to supply test data, enabling parameterized testing.
Subscribe to QABash Weekly ๐ฅ
Dominate โ Stay Ahead of 99% Testers!