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
javafolder → New → Package →com.yourname.selenium.base - Right-click
javafolder → 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.