TestNG Framework Fundamentals
TestNG (Test Next Generation) is a powerful testing framework inspired by JUnit, designed to cover all categories of tests: unit, functional, end-to-end, integration, and more.
TestNG Annotations
Basic Annotations
package com.automation.tests;
import org.testng.annotations.*;
public class TestNGBasics {
@BeforeSuite
public void beforeSuite() {
System.out.println("Before Suite - Runs once before all tests");
// Setup global configurations, database connections
}
@BeforeTest
public void beforeTest() {
System.out.println("Before Test - Runs before <test> tag");
// Initialize test-level resources
}
@BeforeClass
public void beforeClass() {
System.out.println("Before Class - Runs once before class");
// Setup WebDriver, load configurations
}
@BeforeMethod
public void beforeMethod() {
System.out.println("Before Method - Runs before each test");
// Navigate to base URL, clear cookies
}
@Test
public void test1() {
System.out.println("Test 1 executing");
}
@Test
public void test2() {
System.out.println("Test 2 executing");
}
@AfterMethod
public void afterMethod() {
System.out.println("After Method - Runs after each test");
// Take screenshot on failure
}
@AfterClass
public void afterClass() {
System.out.println("After Class - Runs once after class");
// Quit WebDriver
}
@AfterTest
public void afterTest() {
System.out.println("After Test - Runs after <test> tag");
// Cleanup test-level resources
}
@AfterSuite
public void afterSuite() {
System.out.println("After Suite - Runs once after all tests");
// Generate reports, close database connections
}
}
Execution Order
@BeforeSuite
@BeforeTest
@BeforeClass
@BeforeMethod
@Test (test1)
@AfterMethod
@BeforeMethod
@Test (test2)
@AfterMethod
@AfterClass
@AfterTest
@AfterSuite
Test Attributes
public class TestAttributes {
// Test priority - lower runs first
@Test(priority = 1)
public void login() {
System.out.println("Login test");
}
@Test(priority = 2)
public void addProduct() {
System.out.println("Add product test");
}
// Test with description
@Test(description = "Verify user can checkout successfully")
public void checkout() {
System.out.println("Checkout test");
}
// Enabled/Disabled tests
@Test(enabled = false)
public void disabledTest() {
System.out.println("This test is skipped");
}
// Timeout in milliseconds
@Test(timeOut = 5000)
public void testWithTimeout() {
System.out.println("Must complete in 5 seconds");
}
// Expected exception
@Test(expectedExceptions = ArithmeticException.class)
public void testDivisionByZero() {
int result = 10 / 0;
}
// Invocation count - run test multiple times
@Test(invocationCount = 3)
public void testMultipleTimes() {
System.out.println("Running iteration");
}
}
TestNG Assertions
import org.testng.Assert;
import org.testng.asserts.SoftAssert;
public class AssertionExamples {
@Test
public void hardAssertions() {
// Test stops at first failure
// Equality
Assert.assertEquals("actual", "expected", "Strings don't match");
Assert.assertEquals(10, 10);
// True/False
Assert.assertTrue(true, "Should be true");
Assert.assertFalse(false, "Should be false");
// Null checks
Assert.assertNull(null, "Should be null");
Assert.assertNotNull("value", "Should not be null");
// Same object
String str1 = new String("test");
String str2 = str1;
Assert.assertSame(str1, str2, "Should be same object");
// Fail test explicitly
Assert.fail("Test failed intentionally");
}
@Test
public void softAssertions() {
SoftAssert softAssert = new SoftAssert();
// Test continues even after failures
softAssert.assertEquals("actual", "expected", "Failure 1");
softAssert.assertTrue(false, "Failure 2");
softAssert.assertNotNull(null, "Failure 3");
// Collect all failures and report
softAssert.assertAll(); // Fails test if any assertion failed
}
@Test
public void seleniumAssertions() {
WebDriver driver = new ChromeDriver();
driver.get("https://example.com");
// Assert title
Assert.assertEquals(driver.getTitle(), "Expected Title");
// Assert URL
Assert.assertTrue(driver.getCurrentUrl().contains("example"));
// Assert element
WebElement element = driver.findElement(By.id("header"));
Assert.assertTrue(element.isDisplayed(), "Header should be visible");
// Assert text
Assert.assertEquals(element.getText(), "Welcome");
driver.quit();
}
}
Test Dependencies
public class DependentTests {
@Test
public void login() {
System.out.println("Login test");
Assert.assertTrue(true);
}
// Depends on login test
@Test(dependsOnMethods = "login")
public void addProduct() {
System.out.println("Add product - runs only if login passes");
}
// Multiple dependencies
@Test(dependsOnMethods = {"login", "addProduct"})
public void checkout() {
System.out.println("Checkout - runs only if both pass");
}
// Always run even if dependency fails
@Test(dependsOnMethods = "login", alwaysRun = true)
public void logout() {
System.out.println("Logout - runs regardless");
}
}
Grouping Tests
public class GroupedTests {
@Test(groups = "smoke")
public void loginTest() {
System.out.println("Smoke test - Login");
}
@Test(groups = "smoke")
public void logoutTest() {
System.out.println("Smoke test - Logout");
}
@Test(groups = "regression")
public void profileTest() {
System.out.println("Regression test - Profile");
}
@Test(groups = {"smoke", "regression"})
public void searchTest() {
System.out.println("Both smoke and regression");
}
@BeforeGroups("smoke")
public void beforeSmokeTests() {
System.out.println("Before smoke group");
}
@AfterGroups("smoke")
public void afterSmokeTests() {
System.out.println("After smoke group");
}
}
Data-Driven Testing
Using @DataProvider
public class DataDrivenTests {
@DataProvider(name = "loginData")
public Object[][] getLoginData() {
return new Object[][] {
{"user1@test.com", "pass123"},
{"user2@test.com", "pass456"},
{"user3@test.com", "pass789"}
};
}
@Test(dataProvider = "loginData")
public void testLogin(String email, String password) {
System.out.println("Testing with: " + email + " / " + password);
// Perform login
}
@DataProvider(name = "searchData")
public Object[][] getSearchData() {
return new Object[][] {
{"Selenium", 10},
{"TestNG", 15},
{"Maven", 8}
};
}
@Test(dataProvider = "searchData")
public void testSearch(String keyword, int expectedResults) {
System.out.println("Searching: " + keyword);
System.out.println("Expected results: " + expectedResults);
}
}
DataProvider from External File
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;
public class CSVDataProvider {
@DataProvider(name = "csvData")
public Object[][] readCSV() throws Exception {
List<Object[]> records = new ArrayList<>();
BufferedReader br = new BufferedReader(
new FileReader("testdata/users.csv")
);
String line;
while ((line = br.readLine()) != null) {
String[] values = line.split(",");
records.add(values);
}
br.close();
return records.toArray(new Object[records.size()][]);
}
@Test(dataProvider = "csvData")
public void testWithCSV(String username, String password, String expectedResult) {
System.out.println("User: " + username);
System.out.println("Expected: " + expectedResult);
}
}
Parameters from testng.xml
public class ParameterizedTests {
@Parameters({"browser", "url"})
@Test
public void testWithParameters(String browser, String url) {
System.out.println("Browser: " + browser);
System.out.println("URL: " + url);
WebDriver driver;
switch(browser.toLowerCase()) {
case "chrome":
driver = new ChromeDriver();
break;
case "firefox":
driver = new FirefoxDriver();
break;
default:
driver = new ChromeDriver();
}
driver.get(url);
driver.quit();
}
}
testng.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Parameterized Suite">
<test name="Chrome Test">
<parameter name="browser" value="chrome"/>
<parameter name="url" value="https://example.com"/>
<classes>
<class name="com.automation.tests.ParameterizedTests"/>
</classes>
</test>
<test name="Firefox Test">
<parameter name="browser" value="firefox"/>
<parameter name="url" value="https://example.com"/>
<classes>
<class name="com.automation.tests.ParameterizedTests"/>
</classes>
</test>
</suite>
Parallel Execution
testng.xml with parallel execution:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Parallel Suite" parallel="tests" thread-count="3">
<test name="Test 1">
<classes>
<class name="com.automation.tests.LoginTest"/>
</classes>
</test>
<test name="Test 2">
<classes>
<class name="com.automation.tests.SearchTest"/>
</classes>
</test>
<test name="Test 3">
<classes>
<class name="com.automation.tests.CheckoutTest"/>
</classes>
</test>
</suite>
Parallel options:
parallel="tests"- Run<test>tags in parallelparallel="classes"- Run classes in parallelparallel="methods"- Run methods in parallelthread-count="3"- Number of threads
Listeners
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;
public class TestListener implements ITestListener {
@Override
public void onStart(ITestContext context) {
System.out.println("Test Suite Started: " + context.getName());
}
@Override
public void onTestStart(ITestResult result) {
System.out.println("Test Started: " + 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());
// Take screenshot
// Log error details
}
@Override
public void onTestSkipped(ITestResult result) {
System.out.println("Test Skipped: " + result.getName());
}
@Override
public void onFinish(ITestContext context) {
System.out.println("Test Suite Finished: " + context.getName());
}
}
Enable listener in testng.xml:
<suite name="Suite with Listener">
<listeners>
<listener class-name="com.automation.listeners.TestListener"/>
</listeners>
<test name="Test">
<classes>
<class name="com.automation.tests.SampleTest"/>
</classes>
</test>
</suite>
Next Steps
In the next module, we’ll explore advanced techniques like handling dynamic content, working with APIs, and performance optimization.
Key Takeaways
✅ TestNG annotations control test execution flow
✅ Data providers enable data-driven testing
✅ Groups and dependencies organize test suites
✅ Parallel execution speeds up test runs