Selenium with TestNG
TestNG is a Java testing framework, inspired by JUnit but designed for broader test configuration needs, that pairs naturally with Selenium WebDriver to structure, sequence, and report browser automation suites. Where raw Selenium only drives a browser, TestNG supplies annotations for setup and teardown, XML-driven suite configuration, grouping, and built-in HTML reports, turning a pile of WebDriver scripts into an organized, repeatable regression suite.
Cricket analogy: Just as a cricket team needs a fixed batting order and designated roles (opener, finisher, death bowler) rather than eleven players improvising, TestNG imposes a defined lifecycle and structure on what would otherwise be ad-hoc Selenium scripts.
TestNG Annotations and the Test Lifecycle
TestNG exposes a rich set of lifecycle annotations: @BeforeSuite and @AfterSuite run once per suite, @BeforeClass/@AfterClass once per class, @BeforeMethod/@AfterMethod before and after every @Test method, and @BeforeTest/@AfterTest around the <test> tag in testng.xml. In a Selenium context this maps cleanly onto browser lifecycle management — @BeforeMethod typically instantiates a fresh WebDriver and navigates to the base URL, while @AfterMethod calls driver.quit() to close the browser and release resources, guaranteeing test isolation even if a prior test failed.
Cricket analogy: The toss, the innings break, and the post-match presentation happen at fixed points regardless of how the middle overs play out, just as @BeforeMethod and @AfterMethod bracket every @Test method regardless of what happens inside it.
Grouping, Prioritization, and Parallel Execution
TestNG lets you tag tests with groups (e.g., groups = {"smoke", "regression"}) so testng.xml can select a subset to run, order execution deterministically with priority or dependsOnMethods/dependsOnGroups, and run classes or methods in parallel via the parallel attribute (methods, classes, or tests) combined with thread-count. For Selenium suites this is what makes a 500-test regression pack run in minutes instead of hours by spreading independent browser sessions across threads, while still guaranteeing that, say, a login test runs before tests that depend on being logged in.
Cricket analogy: A T20 franchise picks an XI suited to the format (aggressive openers for powerplay) the way TestNG groups let you pick a 'smoke' XI of tests, while overs bowled in parallel by different bowlers across matches mirrors parallel thread execution.
// LoginTest.java
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.By;
import org.testng.Assert;
import org.testng.annotations.*;
public class LoginTest {
private WebDriver driver;
@BeforeMethod
public void setUp() {
driver = new ChromeDriver();
driver.get("https://example.com/login");
}
@Test(groups = {"smoke", "regression"}, priority = 1)
public void loginWithValidCredentials() {
driver.findElement(By.id("username")).sendKeys("qa_user");
driver.findElement(By.id("password")).sendKeys("Secr3t!");
driver.findElement(By.id("loginBtn")).click();
String header = driver.findElement(By.cssSelector("h1.welcome")).getText();
Assert.assertEquals(header, "Welcome, qa_user");
}
@Test(groups = {"regression"}, dependsOnMethods = "loginWithValidCredentials")
public void logoutClearsSession() {
driver.findElement(By.id("logoutBtn")).click();
Assert.assertTrue(driver.findElement(By.id("loginBtn")).isDisplayed());
}
@AfterMethod
public void tearDown() {
if (driver != null) driver.quit();
}
}
<!-- testng.xml -->
<suite name="RegressionSuite" parallel="methods" thread-count="4">
<test name="LoginFlow">
<groups>
<run>
<include name="smoke"/>
</run>
</groups>
<classes>
<class name="LoginTest"/>
</classes>
</test>
</suite>
The testng.xml suite file is the single source of truth for which groups, classes, and parallel mode a given run uses — CI pipelines typically maintain separate XML files (smoke.xml, regression.xml, nightly.xml) pointing at the same test classes but selecting different groups, so you never need to change Java code to change what a pipeline stage runs.
TestNG Reporting and Listeners
TestNG automatically emits an emailable-report.html and an XML report (testng-results.xml) after every run, summarizing pass/fail/skip counts per method, and these integrate directly with CI tools like Jenkins, which can parse the XML for trend graphs. Beyond the default output, implementing ITestListener or IReporter interfaces lets you hook into events like onTestFailure to capture a Selenium screenshot at the moment of failure, or onTestSuccess to log timing — a pattern most real-world Selenium-TestNG frameworks use to attach failure screenshots automatically to reports like Extent Reports or Allure.
Cricket analogy: A scorecard published after a match shows every batsman's runs and every bowler's figures automatically; TestNG's emailable-report.html is that auto-generated scorecard for your test suite, with a listener acting like a broadcaster cutting to a replay the instant a wicket (failure) falls.
- TestNG supplies lifecycle annotations (@BeforeSuite, @BeforeClass, @BeforeMethod, @Test, @AfterMethod, @AfterClass, @AfterSuite) that structure Selenium browser setup and teardown.
- @BeforeMethod/@AfterMethod are the most common pairing for Selenium: instantiate WebDriver before each test, call driver.quit() after, guaranteeing isolation.
- Groups (groups = {...}) let testng.xml select subsets of tests (smoke vs regression) without changing Java code.
- priority and dependsOnMethods/dependsOnGroups control execution order and gate dependent tests.
- parallel="methods|classes|tests" with thread-count drastically cuts suite runtime by running independent Selenium sessions concurrently.
- testng.xml is the configuration file that ties classes, groups, and parallel mode together for a given CI run.
- ITestListener/IReporter hooks (onTestFailure, etc.) are the standard way to auto-capture Selenium screenshots and feed rich reports like Extent or Allure.
Practice what you learned
1. Which TestNG annotation runs exactly once before any test method in a class executes?
2. In a Selenium + TestNG framework, where should driver.quit() typically be placed to guarantee cleanup even after a test failure?
3. What does the 'dependsOnMethods' attribute control?
4. Which testng.xml attribute lets you run multiple test methods concurrently across threads?
5. What is the primary purpose of implementing ITestListener in a Selenium-TestNG framework?
Was this page helpful?
You May Also Like
Selenium with JUnit
Learn how JUnit 5's lifecycle annotations, extension model, and tagging integrate with Selenium WebDriver to build maintainable Java test suites.
Page Object Model (POM)
Understand the Page Object Model design pattern for organizing Selenium tests around reusable, maintainable page classes instead of scattered locators.
Data-Driven Testing
Learn how to separate test logic from input data in Selenium frameworks using TestNG's @DataProvider and JUnit 5's @ParameterizedTest.