TestNG 7 dropped Java 8 long ago — pin to Java 11+ everywhere.
@BeforeMethod / @AfterMethod /
@DataProvider + group filters from testng.xml
are the defining feature vs JUnit — lean on them. Listeners auto-discover via
META-INF/services/org.testng.ITestNGListener. Soft assertions live in
org.testng.asserts.SoftAssert. This sheet pins to TestNG 7.10+.
Maven · Gradle · runSetup
bash
org.testngtestng7.10.2testmaven-surefire-plugin3.2.5src/test/resources/testng.xml
# Gradle — build.gradle.kts
# testImplementation("org.testng:testng:7.10.2")
# tasks.test { useTestNG { suiteXmlFiles += file("testng.xml") } }
# Run
mvn test # all tests in the suite
mvn test -Dgroups="smoke,api" # group filter
mvn test -Dtest=LoginTest#testValid # single method
mvn test -DsuiteXmlFile=integration.xml # alternate suite
gradle test --tests com.acme.LoginTest
onTestFailure → ((TakesScreenshot) driver).getScreenshotAs(...) → attach to report.
RemoteWebDriver + Grid hub URL
Run UI tests across a Selenium Grid.
Allure @Step / @Attachment
Step-by-step report + screenshots / traces.
Login flow · data-drivenEnd-to-end · LoginTest
Class-level Chrome lifecycle, data-provider for credentials, group + dependency to wire a downstream test.
javascript
package com.acme.tests;
import org.testng.annotations.*;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import static org.testng.Assert.*;
public class LoginTest {
private WebDriver driver;
@BeforeClass(alwaysRun = true)
public void setUpBrowser() {
ChromeOptions opts = new ChromeOptions();
opts.addArguments("--headless=new", "--window-size=1280,800");
driver = new ChromeDriver(opts);
}
@AfterClass(alwaysRun = true)
public void tearDown() {
if (driver != null) driver.quit(); // always clean up
}
@DataProvider(name = "users")
public Object[][] users() {
return new Object[][] {
{ "ana@x.com", "secret", true },
{ "bob@x.com", "wrong", false },
};
}
@Test(groups = {"smoke"}, dataProvider = "users",
description = "Login with valid + invalid creds")
public void canLogIn(String email, String pw, boolean ok) {
driver.get("https://example.com/login");
new LoginPage(driver).fill(email, pw).submit();
assertEquals(driver.getCurrentUrl().contains("/dashboard"), ok);
}
@Test(dependsOnMethods = "canLogIn", groups = {"regression"})
public void canViewDashboard() {
assertTrue(driver.getPageSource().contains("Welcome"));
}
}
Best practiceGood to know
Remember the (actual, expected) order in Assert.assertEquals.
TestNG’s order is the opposite of JUnit. Swapping them flips the diff in the report — the test still passes / fails correctly, but the message is misleading. Migrating teams burn an afternoon on this.
Use alwaysRun=true on cleanup hooks.
Without it, @AfterClass is skipped when a @BeforeClass or dependent test fails — leaving DB rows, browsers, or processes around.
Filter groups in testng.xml, not by commenting out @Test.
Mark each test with groups={"smoke","regression"} once, then build suites for each CI lane. Same code, different filter — no risk of forgetting a commented-out test.
Common trapsWatch out for
parallel="methods" shares one class instance across threads.
Mutable instance fields race. Use ThreadLocal for the driver / state, or switch to parallel="classes" / "instances" if your tests assume isolation.
priority is a sort, not a dependency.
Priority orders tests within the same instance but doesn’t guarantee execution — failures don’t cascade. Use dependsOnMethods / dependsOnGroups for real ordering.
SoftAssert without .assertAll() silently passes.
Collected failures only fire when assertAll() is called. Forget it and you get a green test that should be red. Put assertAll() at the end — or call it from an @AfterMethod on a shared SoftAssert.
TestNG is a Java testing framework inspired by JUnit and NUnit but with additional features for enterprise testing. It supports test suites, parallel execution, data-driven tests via @DataProvider, dependency ordering, grouping, and flexible configuration through testng.xml. It is widely used for API, integration, and Selenium UI test automation.
What is the difference between TestNG and JUnit?
TestNG and JUnit 5 are both mature Java testing frameworks. TestNG has built-in suite XML configuration, native parallel test support, and @DataProvider for parameterized tests without needing extensions. JUnit 5 has a more modular architecture with @ParameterizedTest and extensions. JUnit 5 is more common for unit tests; TestNG is popular in Selenium/API automation stacks.
How does @DataProvider work in TestNG?
@DataProvider annotates a method that returns an Object[][] (or Iterator<Object[]>) of input sets. Reference it from a test method with @Test(dataProvider='myProvider'). TestNG runs the test once per row, passing each array as arguments. Add parallel=true to the annotation to run data sets concurrently.
What is testng.xml used for?
testng.xml is the suite configuration file. It defines which test classes or packages to run, organizes them into suites and tests, sets thread counts for parallel execution, includes or excludes groups, and passes parameters to tests. Running mvn test or gradle test picks it up via the surefire/testng plugin configuration.
How does parallel test execution work in TestNG?
Set parallel='methods', 'classes', 'tests', or 'instances' in the <suite> tag of testng.xml, along with thread-count='N'. Methods parallelism runs individual @Test methods concurrently; tests parallelism runs each <test> block in its own thread. Ensure test methods are thread-safe — use ThreadLocal for WebDriver or database connections to avoid sharing state.
Is TestNG free and open source?
Yes. TestNG is Apache-2.0 licensed and free to use commercially. Add it as a test-scope dependency via Maven Central (org.testng:testng). No subscription is required.