Selenium With TestNG & CI/CD

๐Ÿš€ Selenium Automation Framework Setup Using Eclipse, TestNG, Parallel Execution & CI/CD

In this tutorial, we’ll walk through a complete setup of a scalable Selenium Automation Framework using Java, Eclipse, and TestNG. We’ll also implement parallel test execution to reduce test execution time and improve efficiency.


✅ Prerequisites

  • Java JDK (11 or higher)
  • Eclipse IDE (latest version)
  • TestNG plugin for Eclipse
  • Chrome browser + ChromeDriver


๐Ÿงฑ Step 1: Create a Maven Project in Eclipse

  1. Open Eclipse → File → New → Project → Maven Project
  2. Choose maven-archetype-quickstart → Click Finish
  3. Update pom.xml with the following dependencies:
<dependencies>
  <dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-java</artifactId>
    <version>4.20.0</version>
  </dependency>

  <dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>7.10.1</version>
    <scope>test</scope>
  </dependency>
</dependencies>

๐Ÿ“‚ Step 2: Project Structure

src/
 ├── main/
 │    └── java/
 │         └── base/
 │             └── BaseTest.java
 ├── test/
 │    └── java/
 │         ├── tests/
 │         │     └── SampleTest.java
 │         └── utils/
 │               └── DriverFactory.java
testng.xml

๐Ÿ”ง Step 3: Create BaseTest Class

package base;

import org.testng.annotations.*;
import utils.DriverFactory;
import org.openqa.selenium.WebDriver;

public class BaseTest {
    protected WebDriver driver;

    @BeforeMethod
    @Parameters("browser")
    public void setup(@Optional("chrome") String browser) {
        driver = DriverFactory.initDriver(browser);
    }

    @AfterMethod
    public void tearDown() {
        driver.quit();
    }
}

๐Ÿš— Step 4: Create DriverFactory for Multi-browser Support

package utils;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.edge.EdgeDriver;

public class DriverFactory {
    public static WebDriver initDriver(String browser) {
        if (browser.equalsIgnoreCase("chrome")) {
            return new ChromeDriver();
        } else if (browser.equalsIgnoreCase("edge")) {
            return new EdgeDriver();
        }
        throw new IllegalArgumentException("Browser not supported");
    }
}

๐Ÿงช Step 5: Sample Test Class

package tests;

import base.BaseTest;
import org.testng.annotations.Test;

public class SampleTest extends BaseTest {

    @Test
    public void openGoogle() {
        driver.get("https://www.google.com");
        System.out.println("Title: " + driver.getTitle());
    }
}

๐Ÿ›  Step 6: Configure testng.xml for Parallel Execution

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="ParallelSuite" parallel="tests" thread-count="2">
    <test name="Chrome Test">
        <parameter name="browser" value="chrome"/>
        <classes>
            <class name="tests.SampleTest"/>
        </classes>
    </test>

    <test name="Edge Test">
        <parameter name="browser" value="edge"/>
        <classes>
            <class name="tests.SampleTest"/>
        </classes>
    </test>
</suite>

๐Ÿงช Step 7: Run the Tests

  • Right-click on testng.xml → Run As → TestNG Suite
  • Observe two browser sessions (Chrome and Edge) executing in parallel.

๐Ÿ“Š Step 8: Adding Extent Reports and Screenshot Capture

Enhancing your framework with reporting and screenshots helps you debug faster and share results with stakeholders. We’ll use ExtentReports for beautiful HTML reports and ScreenshotUtil to capture failed test cases.

๐Ÿ–ฅ 1. Add ExtentReportListener.java

This listener will automatically log test execution to an HTML file:

package listeners;

import com.aventstack.extentreports.*;
import com.aventstack.extentreports.reporter.*;
import org.testng.*;

public class ExtentReportListener implements ITestListener {
    private static ExtentReports extent;
    private static ThreadLocal<ExtentTest> test = new ThreadLocal<>();

    public void onStart(ITestContext context) {
        ExtentHtmlReporter htmlReporter = new ExtentHtmlReporter("test-output/ExtentReport.html");
        htmlReporter.config().setTheme(Theme.STANDARD);
        htmlReporter.config().setReportName("Test Execution Report");
        extent = new ExtentReports();
        extent.attachReporter(htmlReporter);
    }

    public void onTestStart(ITestResult result) {
        test.set(extent.createTest(result.getMethod().getMethodName()));
    }

    public void onTestSuccess(ITestResult result) {
        test.get().log(Status.PASS, "Test Passed");
    }

    public void onTestFailure(ITestResult result) {
        test.get().log(Status.FAIL, "Test Failed: " + result.getThrowable());
    }

    public void onTestSkipped(ITestResult result) {
        test.get().log(Status.SKIP, "Test Skipped: " + result.getThrowable());
    }

    public void onFinish(ITestContext context) {
        extent.flush();
    }
}

๐Ÿ“ธ 2. Add ScreenshotUtil.java

package utils;

import org.openqa.selenium.*;
import java.io.*;
import java.nio.file.*;

public class ScreenshotUtil {
    public static String captureScreenshot(WebDriver driver, String screenshotName) {
        File src = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
        String dest = "screenshots/" + screenshotName + ".png";
        try {
            Files.createDirectories(Paths.get("screenshots"));
            Files.copy(src.toPath(), Paths.get(dest), StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return dest;
    }
}

๐Ÿงฉ 3. Register Listener in testng.xml

<suite name="ParallelSuite" parallel="tests" thread-count="2"
       listeners="listeners.ExtentReportListener">

๐ŸŽฏ 4. (Optional) Capture Screenshot on Failure

Inside onTestFailure() method, you can call:

String path = ScreenshotUtil.captureScreenshot(driver, result.getMethod().getMethodName());
test.get().addScreenCaptureFromPath(path);

๐Ÿ“‚ Output Location

  • test-output/ExtentReport.html — Full test summary
  • screenshots/ — Failed test screenshots

✅ Step 9: Implement Page Object Model (POM)

POM promotes better code organization by separating locators and actions from test logic.

๐Ÿ“„ Create a Page Class

package pages;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;

public class GoogleHomePage {
    WebDriver driver;

    @FindBy(name = "q")
    WebElement searchBox;

    public GoogleHomePage(WebDriver driver) {
        this.driver = driver;
        PageFactory.initElements(driver, this);
    }

    public void search(String query) {
        searchBox.sendKeys(query);
        searchBox.submit();
    }
}

๐Ÿ” Use Page in Test

package tests;

import base.BaseTest;
import org.testng.annotations.Test;
import pages.GoogleHomePage;

public class SampleTest extends BaseTest {

    @Test
    public void searchTest() {
        driver.get("https://www.google.com");
        GoogleHomePage google = new GoogleHomePage(driver);
        google.search("Selenium automation");
    }
}

๐Ÿ›  Step 10: Externalize Configuration with config.properties

Use a properties file to manage environment-specific settings.

๐Ÿงพ Create config.properties

browser=chrome
baseUrl=https://www.google.com

๐Ÿ›  Create ConfigReader.java

package utils;

import java.io.FileInputStream;
import java.util.Properties;

public class ConfigReader {
    private static Properties props = new Properties();

    static {
        try {
            FileInputStream fis = new FileInputStream("config.properties");
            props.load(fis);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static String get(String key) {
        return props.getProperty(key);
    }
}

๐Ÿ’ก Use in Your Test

driver.get(ConfigReader.get("baseUrl"));

๐Ÿ”„ Step 11: CI/CD Integration using Jenkins & GitHub Actions

๐Ÿ“ฆ Jenkins

  • Install Jenkins and configure it to use Java & Maven
  • Create a new job and pull from Git
  • Use the following command as your build step:
    mvn clean test

๐Ÿค– GitHub Actions

Add a file .github/workflows/test.yml:

name: Selenium Test

on: [push]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3
      - name: Set up JDK
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'

      - name: Run Maven Tests
        run: mvn clean test

This will automatically run your Selenium tests every time you push to GitHub. You can integrate this with Extent Reports publishing and email notifications too.


๐ŸŽ‰ Final Framework Overview

  • ✅ Modular structure with Page Object Model
  • ๐Ÿ›  Environment management with config file
  • ๐Ÿ“Š HTML reporting and screenshots on failure
  • ⚙️ Parallel test execution using TestNG
  • ๐Ÿ” Fully CI/CD ready with Jenkins and GitHub Actions

๐Ÿ“Œ Best Practices

  • Use Page Object Model for better maintainability.
  • Add a config.properties file for dynamic environment handling.
  • Use WebDriverManager for automatic driver management.
  • Integrate with CI tools like Jenkins/GitHub Actions.

๐Ÿ“ฃ Final Thoughts

You now have a basic yet powerful Selenium framework using Java, TestNG, and Eclipse with parallel execution, extent reports enabled. From here, you can scale it with logging, reports (Allure), reusable utilities, and advanced integrations.

๐Ÿง  Keep iterating and customizing this framework to fit your team's needs. The more modular and readable your tests, the easier they are to scale.

— Karthik | TestAutomate360

Comments