Lesson 9 of 14 ~30 min
Course progress
0%

TestNG Essentials

Master TestNG annotations, assertions, and test configuration

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 parallel
  • parallel="classes" - Run classes in parallel
  • parallel="methods" - Run methods in parallel
  • thread-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

Which annotation runs before each test method?

@BeforeClass
@BeforeMethod
@BeforeTest
@BeforeSuite

What is the purpose of SoftAssert?

To make assertions faster
To skip failing tests
To continue test execution after assertion failures
To assert soft-deleted elements

Which parallel option runs test methods in parallel?

parallel='tests'
parallel='classes'
parallel='suite'
parallel='methods'