Skip to main content
SeleniumDecoded

TestNG and JUnit Integration

Integrate Selenium with TestNG and JUnit test frameworks for structured, maintainable Java tests.

Selenium 3 & 4 Stable

TestNG and JUnit are the two most popular testing frameworks for Java. Both integrate seamlessly with Selenium to provide test organization, assertions, and reporting.

TestNG Setup

Maven Dependencies

<dependencies>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.18.1</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.9.0</version>
<scope>test</scope>
</dependency>
</dependencies>

Basic TestNG Test

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.By;
import org.testng.annotations.*;
import org.testng.Assert;
public class LoginTest {
private WebDriver driver;
@BeforeClass
public void setupClass() {
// Runs once before all tests in this class
System.out.println("Setting up test class");
}
@BeforeMethod
public void setup() {
// Runs before each test method
driver = new ChromeDriver();
driver.manage().window().maximize();
}
@Test(priority = 1)
public void testValidLogin() {
driver.get("https://example.com/login");
driver.findElement(By.id("username")).sendKeys("validuser");
driver.findElement(By.id("password")).sendKeys("validpass");
driver.findElement(By.id("login")).click();
Assert.assertTrue(driver.getCurrentUrl().contains("/dashboard"),
"Should redirect to dashboard");
}
@Test(priority = 2)
public void testInvalidLogin() {
driver.get("https://example.com/login");
driver.findElement(By.id("username")).sendKeys("invalid");
driver.findElement(By.id("password")).sendKeys("wrong");
driver.findElement(By.id("login")).click();
String error = driver.findElement(By.className("error")).getText();
Assert.assertEquals(error, "Invalid credentials");
}
@AfterMethod
public void teardown() {
// Runs after each test method
if (driver != null) {
driver.quit();
}
}
@AfterClass
public void teardownClass() {
// Runs once after all tests in this class
System.out.println("Tests completed");
}
}

TestNG Annotations Reference

AnnotationDescription
@BeforeSuiteBefore all tests in suite
@BeforeClassBefore first test in class
@BeforeMethodBefore each test method
@TestMarks test method
@AfterMethodAfter each test method
@AfterClassAfter last test in class
@AfterSuiteAfter all tests in suite

TestNG Data Providers

import org.testng.annotations.DataProvider;
public class DataDrivenTest {
private WebDriver driver;
@BeforeMethod
public void setup() {
driver = new ChromeDriver();
}
@DataProvider(name = "loginData")
public Object[][] loginDataProvider() {
return new Object[][] {
{"user1", "pass1", true},
{"user2", "pass2", true},
{"invalid", "wrong", false}
};
}
@Test(dataProvider = "loginData")
public void testLogin(String username, String password, boolean shouldPass) {
driver.get("https://example.com/login");
driver.findElement(By.id("username")).sendKeys(username);
driver.findElement(By.id("password")).sendKeys(password);
driver.findElement(By.id("login")).click();
if (shouldPass) {
Assert.assertTrue(driver.getCurrentUrl().contains("/dashboard"));
} else {
Assert.assertTrue(driver.findElement(By.className("error")).isDisplayed());
}
}
@AfterMethod
public void teardown() {
driver.quit();
}
}

TestNG XML Suite

testng.xml
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Regression Suite" parallel="methods" thread-count="3">
<test name="Login Tests">
<classes>
<class name="tests.LoginTest"/>
<class name="tests.RegistrationTest"/>
</classes>
</test>
<test name="Search Tests">
<classes>
<class name="tests.SearchTest"/>
</classes>
</test>
</suite>

JUnit 5 Setup

Maven Dependencies

<dependencies>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.18.1</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
</dependencies>

Basic JUnit 5 Test

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.By;
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.*;
class LoginTest {
private WebDriver driver;
@BeforeAll
static void setupAll() {
// Runs once before all tests
System.out.println("Setting up test class");
}
@BeforeEach
void setup() {
// Runs before each test
driver = new ChromeDriver();
driver.manage().window().maximize();
}
@Test
@DisplayName("Valid user can login successfully")
void testValidLogin() {
driver.get("https://example.com/login");
driver.findElement(By.id("username")).sendKeys("validuser");
driver.findElement(By.id("password")).sendKeys("validpass");
driver.findElement(By.id("login")).click();
assertTrue(driver.getCurrentUrl().contains("/dashboard"),
"Should redirect to dashboard");
}
@Test
@DisplayName("Invalid credentials show error")
void testInvalidLogin() {
driver.get("https://example.com/login");
driver.findElement(By.id("username")).sendKeys("invalid");
driver.findElement(By.id("password")).sendKeys("wrong");
driver.findElement(By.id("login")).click();
String error = driver.findElement(By.className("error")).getText();
assertEquals("Invalid credentials", error);
}
@AfterEach
void teardown() {
if (driver != null) {
driver.quit();
}
}
@AfterAll
static void teardownAll() {
System.out.println("Tests completed");
}
}

JUnit 5 Annotations Reference

AnnotationDescription
@BeforeAllBefore all tests (static)
@BeforeEachBefore each test
@TestMarks test method
@AfterEachAfter each test
@AfterAllAfter all tests (static)
@DisplayNameCustom test name
@DisabledSkip test

JUnit 5 Parameterized Tests

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.*;
class ParameterizedLoginTest {
private WebDriver driver;
@BeforeEach
void setup() {
driver = new ChromeDriver();
}
@ParameterizedTest
@CsvSource({
"user1, pass1, true",
"user2, pass2, true",
"invalid, wrong, false"
})
void testLogin(String username, String password, boolean shouldPass) {
driver.get("https://example.com/login");
driver.findElement(By.id("username")).sendKeys(username);
driver.findElement(By.id("password")).sendKeys(password);
driver.findElement(By.id("login")).click();
if (shouldPass) {
assertTrue(driver.getCurrentUrl().contains("/dashboard"));
} else {
assertTrue(driver.findElement(By.className("error")).isDisplayed());
}
}
@ParameterizedTest
@ValueSource(strings = {"chrome", "firefox", "edge"})
void testBrowsers(String browser) {
// Test across browsers
}
@AfterEach
void teardown() {
driver.quit();
}
}

Base Test Class Pattern

// For TestNG
public class BaseTest {
protected WebDriver driver;
protected WebDriverWait wait;
@BeforeMethod
public void setup() {
driver = DriverFactory.getDriver();
wait = new WebDriverWait(driver, Duration.ofSeconds(10));
driver.manage().window().maximize();
}
@AfterMethod
public void teardown(ITestResult result) {
if (result.getStatus() == ITestResult.FAILURE) {
takeScreenshot(result.getName());
}
DriverFactory.quitDriver();
}
protected void takeScreenshot(String name) {
// Screenshot logic
}
}
// Tests extend BaseTest
public class LoginTest extends BaseTest {
@Test
public void testLogin() {
driver.get("https://example.com");
// Test logic using inherited driver
}
}

TestNG vs JUnit 5

FeatureTestNGJUnit 5
Parallel executionBuilt-in XML configJupiter parallel config
Data providers@DataProvider@ParameterizedTest
Test groups@Test(groups="")@Tag
DependenciesdependsOnMethods@Order
Suite filesXML-basedProgrammatic
ReportingBuilt-in HTMLRequires plugins

Next Steps