← Blog

"Selenium Series #2: Project Setup — Maven, Dependencies and Your First Structured Test"

Set up a production-ready Maven project with Selenium WebDriver, TestNG and proper folder structure. Never download jars manually again.

reading now
views
comments

Series Navigation

Part 1: Introduction to Selenium WebDriver

Part 3: Browser Drivers — ChromeDriver, GeckoDriver and WebDriverManager


Why Maven?

Without a build tool, you manually download .jar files, add them to your classpath, and deal with version conflicts yourself. Maven automates all of this:

  • Downloads dependencies from Maven Central automatically
  • Manages versions and transitive dependencies
  • Builds and runs tests with a single command
  • Integrates with CI/CD — Jenkins, GitLab CI, GitHub Actions all understand Maven

Create the Maven Project in IntelliJ

File → New → Project → Maven

New Project
├── Project SDK:   Java 11 (or 8+)
├── GroupId:       com.yourname.selenium
├── ArtifactId:    selenium-training
├── Version:       1.0-SNAPSHOT
└── Project name:  selenium-training

Click Finish. IntelliJ creates this structure:

selenium-training/
├── pom.xml                    ← Maven configuration
└── src/
    ├── main/
    │   └── java/              ← application code (we won't use this)
    └── test/
        └── java/              ← ALL test code goes here

The pom.xml — Complete Configuration

Replace the generated pom.xml with this:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.yourname.selenium</groupId>
    <artifactId>selenium-training</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <!-- Java version -->
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <!-- Dependency versions — update these when new versions release -->
        <selenium.version>3.141.59</selenium.version>
        <testng.version>7.1.0</testng.version>
        <webdrivermanager.version>4.2.2</webdrivermanager.version>
    </properties>

    <dependencies>
        <!-- Selenium WebDriver -->
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>${selenium.version}</version>
        </dependency>

        <!-- TestNG test framework -->
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>${testng.version}</version>
            <scope>test</scope>
        </dependency>

        <!-- WebDriverManager — auto-downloads browser drivers -->
        <dependency>
            <groupId>io.github.bonigarcia</groupId>
            <artifactId>webdrivermanager</artifactId>
            <version>${webdrivermanager.version}</version>
        </dependency>

        <!-- Apache Commons IO — for file operations -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.8.0</version>
        </dependency>

        <!-- Log4j — for logging -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.14.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- Maven Surefire — runs TestNG tests -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0-M5</version>
                <configuration>
                    <!-- Point to your TestNG XML suite file -->
                    <suiteXmlFiles>
                        <suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile>
                    </suiteXmlFiles>
                </configuration>
            </plugin>

            <!-- Maven Compiler -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

After saving, IntelliJ shows a Maven notification. Click "Load Maven Changes" (or the elephant icon). Maven downloads all dependencies — this takes 1-2 minutes on first run.

Downloading dependencies:
✓ selenium-java-3.141.59.jar          (8.2 MB)
✓ selenium-chrome-driver-3.141.59.jar (48 KB)
✓ selenium-remote-driver-3.141.59.jar (290 KB)
✓ testng-7.1.0.jar                    (880 KB)
✓ webdrivermanager-4.2.2.jar          (360 KB)
... (and ~40 transitive dependencies)

Proper Project Structure

Expand the test folder to match this structure:

src/test/
├── java/
│   └── com/
│       └── yourname/
│           └── selenium/
│               ├── base/
│               │   └── BaseTest.java      ← shared setup/teardown
│               ├── pages/
│               │   └── LoginPage.java     ← page objects (Part 8)
│               └── tests/
│                   └── LoginTest.java     ← test classes
└── resources/
    ├── testng.xml                         ← TestNG suite config
    └── config.properties                  ← environment config

Create the folder structure in IntelliJ:

  • Right-click java folder → New → Package → com.yourname.selenium.base
  • Right-click java folder → New → Package → com.yourname.selenium.tests
  • Right-click resources → New → File → testng.xml

The Base Test Class

Every test class extends BaseTest, which handles browser setup and teardown:

// src/test/java/com/yourname/selenium/base/BaseTest.java
package com.yourname.selenium.base;

import io.github.bonigarcia.wdm.WebDriverManager;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;

public class BaseTest {

    // ThreadLocal makes driver thread-safe for parallel test execution
    protected static ThreadLocal<WebDriver> driverThreadLocal = new ThreadLocal<>();

    // Gets the driver for the current thread
    protected WebDriver getDriver() {
        return driverThreadLocal.get();
    }

    @BeforeMethod
    public void setUp() {
        // WebDriverManager downloads the correct ChromeDriver version automatically
        WebDriverManager.chromedriver().setup();

        // Configure Chrome options
        ChromeOptions options = new ChromeOptions();
        options.addArguments("--start-maximized");         // open maximized
        options.addArguments("--disable-notifications");   // block notifications
        options.addArguments("--disable-infobars");        // hide "Chrome is controlled" bar

        // Create new driver and store in ThreadLocal
        WebDriver driver = new ChromeDriver(options);
        driverThreadLocal.set(driver);

        // Set implicit wait — explained in Part 6
        // driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
    }

    @AfterMethod
    public void tearDown() {
        WebDriver driver = getDriver();
        if (driver != null) {
            driver.quit();          // close browser and kill process
            driverThreadLocal.remove(); // remove from ThreadLocal to prevent memory leaks
        }
    }
}

Your First Real Test Class

// src/test/java/com/yourname/selenium/tests/GoogleSearchTest.java
package com.yourname.selenium.tests;

import com.yourname.selenium.base.BaseTest;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.testng.Assert;
import org.testng.annotations.Test;

public class GoogleSearchTest extends BaseTest {

    @Test
    public void searchForSelenium() {
        WebDriver driver = getDriver();

        // Navigate to Google
        driver.get("https://www.google.com");

        // Verify page title
        Assert.assertTrue(driver.getTitle().contains("Google"),
            "Expected title to contain 'Google', got: " + driver.getTitle());

        // Find the search box and type
        WebElement searchBox = driver.findElement(By.name("q"));
        searchBox.sendKeys("Selenium WebDriver");
        searchBox.sendKeys(Keys.RETURN);  // press Enter

        // Wait for results (basic approach — we'll improve in Part 6)
        // Verify results page title changes
        Assert.assertTrue(driver.getTitle().contains("Selenium WebDriver"),
            "Search results title should contain query");

        System.out.println("✓ Search test passed. Title: " + driver.getTitle());
    }

    @Test
    public void verifyGoogleHomepageLogo() {
        WebDriver driver = getDriver();
        driver.get("https://www.google.com");

        // Find the Google logo image
        WebElement logo = driver.findElement(By.id("hplogo"));

        // Verify it's displayed
        Assert.assertTrue(logo.isDisplayed(), "Google logo should be visible");
        System.out.println("✓ Logo test passed");
    }
}

The TestNG XML Suite File

<!-- src/test/resources/testng.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">

<suite name="Selenium Training Suite" verbose="2">

    <test name="Google Tests">
        <classes>
            <class name="com.yourname.selenium.tests.GoogleSearchTest"/>
        </classes>
    </test>

</suite>

Running Your Tests

From IntelliJ:

  • Right-click testng.xml → Run
  • Right-click any test class → Run
  • Right-click any test method → Run

From Terminal (Maven):

# Run all tests
mvn test

# Run a specific test class
mvn test -Dtest=GoogleSearchTest

# Run a specific method
mvn test -Dtest=GoogleSearchTest#searchForSelenium

# Skip tests during build
mvn install -DskipTests

Expected console output:

[INFO] --- maven-surefire-plugin:3.0.0-M5:test ---
[INFO] Running TestSuite
...
✓ Search test passed. Title: Selenium WebDriver - Google Search
✓ Logo test passed

[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS

The config.properties File

Hardcoding URLs and credentials in test code is bad practice. Use a properties file:

# src/test/resources/config.properties
base.url=https://www.example.com
browser=chrome
implicit.wait=10
explicit.wait=20
username=testuser@example.com
password=TestPassword123

Read it in BaseTest:

// Add to BaseTest.java
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

public class BaseTest {
    protected static Properties config;

    static {
        config = new Properties();
        try {
            FileInputStream fis = new FileInputStream(
                "src/test/resources/config.properties"
            );
            config.load(fis);
        } catch (IOException e) {
            throw new RuntimeException("Cannot load config.properties", e);
        }
    }

    // Use like this in tests:
    // driver.get(config.getProperty("base.url"));
    // String username = config.getProperty("username");
}

Common Setup Errors and Fixes

Error: SessionNotCreatedException: session not created
       This version of ChromeDriver only supports Chrome 80
Fix:   Use WebDriverManager — it auto-matches ChromeDriver to your Chrome version

Error: NoClassDefFoundError: org/openqa/selenium/WebDriver  
Fix:   Check pom.xml has selenium-java dependency, reload Maven

Error: WebDriverException: chrome not reachable
Fix:   Chrome is already running with different flags — close all Chrome windows

Error: Cannot find symbol: WebDriverManager
Fix:   Add webdrivermanager dependency to pom.xml and reload Maven

What's Next

In Part 3 we go deep on browser drivers — how ChromeDriver, GeckoDriver and EdgeDriver work, how WebDriverManager solves the version-mismatch problem, and how to configure browsers with options and capabilities.

Discussion

Loading...

Leave a Comment

All comments are reviewed before appearing. No links please.

0 / 1000