Lesson 1 of 10 · Lesson + Lab · 75 min · Free preview

Java Essentials for Testers & Maven Project Setup

Learn the Java that Selenium frameworks really use and set up a Java 17 + Maven + TestNG project in IntelliJ that the rest of the course builds on.

Why this matters on the job

Walk into an automation interview at a service company (TCS, Infosys, Wipro, Cognizant, Capgemini, Accenture) or a product company in Bengaluru, Pune or Hyderabad and the first technical round is usually Java, not Selenium: reverse a string, find duplicates, explain final vs finally, explain why we write WebDriver driver = new ChromeDriver(). Candidates who know Selenium commands but freeze on Java rarely clear that round.

On the job it is the same story. Your daily work is reading and extending a framework written in Java: page classes, base classes, utilities, listeners and data readers. This lesson gives you exactly the Java a tester needs - no more - and builds the Maven project that every later lesson in this course grows into a full framework.

Concepts

The Java you will actually use in a Selenium framework

Java conceptWhere you meet it in the framework
Class and objectEvery page (LoginPage) and every test class
Inheritance (extends)LoginTest extends BaseTest, LoginPage extends BasePage
InterfaceWebDriver, WebElement, ITestListener are interfaces; ChromeDriver implements WebDriver
EncapsulationLocators are private; tests call public business methods like loginAs()
Collections (List, Set, Map)findElements() returns List<WebElement>; test data rows as Map<String, String>
ExceptionsNoSuchElementException, TimeoutException; try-with-resources for files
static and finalConstants, utility classes, the ThreadLocal driver holder
Lambdas and streamsTurning a list of price elements into numbers and checking the sort order

Here is a preview of how these ideas show up together in real test code (you will run this kind of code from lesson 2):

WebDriver driver = new ChromeDriver();      // interface reference, class object (upcasting)
List<WebElement> prices = driver.findElements(By.className("inventory_item_price"));

List<Double> values = prices.stream()
        .map(WebElement::getText)                         // "$29.99"
        .map(t -> Double.parseDouble(t.replace("$", "")))  // 29.99
        .toList();                                          // Java 16+

The toolchain

ToolVersion used in this courseWhy
JDK17 LTS (Eclipse Temurin); 21 also worksLong-term support, records, switch expressions, var
Maven3.9.xDownloads libraries, compiles, runs TestNG through the Surefire plugin
IntelliJ IDEACommunity edition (free)Best Maven/TestNG integration, refactoring, debugger
Git2.xEvery framework lives in a repository (lesson 9 and capstone)

Maven essentials: the pom.xml declares dependencies by coordinates (groupId, artifactId, version). Maven downloads them into ~/.m2/repository. Source code lives in the standard layout src/main/java and src/test/java; resources (config, test data) go in src/test/resources. The test phase compiles everything and runs tests through the Surefire plugin. In this course all framework code (pages, utilities, tests) lives under src/test/java, the common convention for test-only projects.

Hands-on Lab: Install the toolchain and run your first Maven + TestNG build

  1. Install JDK 17 and verify. macOS: brew install --cask temurin@17. Windows: winget install EclipseAdoptium.Temurin.17.JDK. Ubuntu: sudo apt install openjdk-17-jdk. Then run:
    java -version
    # expected: openjdk version "17.0.x" ...
    Set JAVA_HOME to the JDK folder if mvn -v later reports a different Java.
  2. Install Maven. macOS: brew install maven. Ubuntu: sudo apt install maven. Windows: download the binary zip from maven.apache.org, extract to C:\tools\maven and add its bin folder to PATH. Verify:
    mvn -v
    # expected: Apache Maven 3.9.x ... Java version: 17.0.x
  3. Generate the project skeleton:
    mvn archetype:generate -DgroupId=com.qaji -DartifactId=selenium-framework \
      -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.5 \
      -DinteractiveMode=false
    cd selenium-framework
    Delete the generated App.java and AppTest.java - we will use TestNG, not JUnit.
  4. Replace pom.xml with the version below. It pins Java 17 and adds Selenium and TestNG.
  5. <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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>com.qaji</groupId>
      <artifactId>selenium-framework</artifactId>
      <version>1.0-SNAPSHOT</version>
    
      <properties>
        <maven.compiler.release>17</maven.compiler.release>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <!-- Check Maven Central for the newest 4.x / 7.x before you start -->
        <selenium.version>4.35.0</selenium.version>
        <testng.version>7.11.0</testng.version>
      </properties>
    
      <dependencies>
        <dependency>
          <groupId>org.seleniumhq.selenium</groupId>
          <artifactId>selenium-java</artifactId>
          <version>${selenium.version}</version>
        </dependency>
        <dependency>
          <groupId>org.testng</groupId>
          <artifactId>testng</artifactId>
          <version>${testng.version}</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
    
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.14.0</version>
          </plugin>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>3.5.3</version>
          </plugin>
        </plugins>
      </build>
    </project>
  6. Open the folder in IntelliJ (File > Open > select pom.xml > Open as Project) and click Load Maven Changes when prompted.
  7. Create src/test/java/com/qaji/utils/PriceUtils.java. It practises static methods, exceptions, collections and streams - the exact skills used later to validate product prices on SauceDemo.
    package com.qaji.utils;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    import java.util.Map;
    import java.util.stream.Collectors;
    
    public final class PriceUtils {
    
        private PriceUtils() { }   // utility class: no objects needed
    
        /** "$29.99" -> 29.99 */
        public static double parsePrice(String text) {
            if (text == null || text.isBlank()) {
                throw new IllegalArgumentException("Price text is empty");
            }
            return Double.parseDouble(text.replace("$", "").replace(",", "").trim());
        }
    
        /** true when the list is already in ascending order */
        public static boolean isSortedLowToHigh(List<Double> prices) {
            List<Double> copy = new ArrayList<>(prices);
            Collections.sort(copy);
            return copy.equals(prices);
        }
    
        /** returns only the items that appear more than once, with their count */
        public static Map<String, Long> countDuplicates(List<String> items) {
            return items.stream()
                    .collect(Collectors.groupingBy(s -> s, Collectors.counting()))
                    .entrySet().stream()
                    .filter(e -> e.getValue() > 1)
                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
        }
    }
  8. Create src/test/java/com/qaji/utils/PriceUtilsTest.java:
    package com.qaji.utils;
    
    import java.util.List;
    import java.util.Map;
    import org.testng.Assert;
    import org.testng.annotations.Test;
    
    public class PriceUtilsTest {
    
        @Test
        public void parsesDollarPrice() {
            Assert.assertEquals(PriceUtils.parsePrice("$29.99"), 29.99, 0.001);
        }
    
        @Test
        public void detectsSortedList() {
            Assert.assertTrue(PriceUtils.isSortedLowToHigh(List.of(7.99, 9.99, 15.99)));
            Assert.assertFalse(PriceUtils.isSortedLowToHigh(List.of(9.99, 7.99)));
        }
    
        @Test
        public void findsDuplicateProducts() {
            Map<String, Long> dups = PriceUtils.countDuplicates(
                    List.of("Backpack", "Bike Light", "Backpack"));
            Assert.assertEquals(dups, Map.of("Backpack", 2L));
        }
    
        @Test(expectedExceptions = IllegalArgumentException.class)
        public void rejectsEmptyPrice() {
            PriceUtils.parsePrice("   ");
        }
    }
  9. Run the build from the project root:
    mvn clean test
    # expected (end of output):
    # Tests run: 4, Failures: 0, Errors: 0, Skipped: 0
    # BUILD SUCCESS
  10. Break it on purpose: change 29.99 to 29.98 in the first test, run again and read the failure message (expected [29.98] but found [29.99]). Revert, then commit: git init && git add . && git commit -m "Project skeleton".

Common mistakes

  • JAVA_HOME still points to Java 8 - Maven then fails with release version 17 not supported. Fix JAVA_HOME and reopen the terminal.
  • Mixing JUnit and TestNG imports: org.junit.Assert in a TestNG test compiles only if JUnit is on the classpath and confuses reports. Always import org.testng.Assert.
  • Naming a test class PriceCheck: Surefire only picks classes matching *Test, Test*, *Tests or *TestCase by default, so the build says Tests run: 0.
  • Comparing strings with == instead of equals() - a classic interview trap and a real source of false failures.
  • Editing pom.xml but forgetting to reload Maven in IntelliJ, then wondering why imports are red.

Real-world assignment

Your test lead says: "Set up the shared automation repo before the sprint starts." Deliver the following in your own GitHub repository:

  • Packages com.qaji.base, pages, tests, utils created (empty placeholder classes are fine).
  • A StringUtils class with three interview favourites and a TestNG test for each: reverse a string, count occurrences of each character (return a Map<Character, Integer>), and return the second-highest value from a List<Double>.
  • A README.md with prerequisites (JDK 17, Maven 3.9) and the command mvn clean test.
  • A .gitignore containing target/, .idea/ and *.iml.

Key takeaways

  • Interview round one is Java: classes, inheritance, interfaces, collections, exceptions and strings.
  • WebDriver driver = new ChromeDriver() is upcasting to an interface - it lets the same code run on any browser.
  • Maven manages dependencies and runs tests; pom.xml plus the standard folder layout is the backbone of every framework.
  • Keep test class names ending in Test so Surefire discovers them.
  • Commit a clean, building skeleton before writing any Selenium code.

🧪 Practical checklist

Do each task yourself and tick it off. All tasks are required to complete this lesson.

🎤 Interview questions

Why do we write WebDriver driver = new ChromeDriver() instead of ChromeDriver driver = new ChromeDriver()?

WebDriver is an interface implemented by every browser driver. Coding to the interface (upcasting) lets the same framework code run on Chrome, Firefox or Edge by changing only the object creation.

What is the difference between List and Set, and where do you use them in Selenium?

A List keeps insertion order and allows duplicates (findElements returns List<WebElement>); a Set has no duplicates and is what getWindowHandles() returns.

What is pom.xml and what does mvn test do?

pom.xml is Maven's project descriptor holding coordinates, dependencies and plugins. mvn test runs the lifecycle up to the test phase: resolves dependencies, compiles main and test code and runs tests through Surefire.

Explain final, finally and finalize.

final makes a variable constant, a method non-overridable or a class non-inheritable; finally is a block that always runs after try/catch (used to quit the driver); finalize is a deprecated Object method called by the garbage collector.

Checked vs unchecked exceptions - give a Selenium example.

Checked exceptions (IOException when reading a config file) must be caught or declared; unchecked ones extend RuntimeException, like NoSuchElementException and TimeoutException in Selenium.

📝 Quiz, progress tracking & certificate

You're reading a free preview. Premium members tick off labs, take the quiz, unlock all 10 lessons and earn a verifiable certificate.

💎 Unlock with Premium Premium login
✓ You're subscribed! Job alerts arrive daily at 9 AM.
Scroll to Top