100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Testing

Selenium with JUnit

Learn how JUnit 5's lifecycle annotations, extension model, and tagging integrate with Selenium WebDriver to build maintainable Java test suites.

Test Framework IntegrationIntermediate8 min readJul 10, 2026
Analogies

Selenium with JUnit

JUnit is Java's most widely used unit testing framework, and JUnit 5 (the Jupiter engine) is a common alternative to TestNG for structuring Selenium WebDriver suites, especially in projects already standardized on JUnit for unit tests. JUnit 5 splits into three modules — Jupiter (the new programming model with annotations like @Test), Vintage (backward compatibility for JUnit 3/4), and the Platform (the launcher CI tools and IDEs hook into) — and its annotation set (@BeforeEach, @AfterEach, @BeforeAll, @AfterAll) maps onto Selenium's browser lifecycle in essentially the same way TestNG's does, just with different names and a more extensible architecture via the @ExtendWith mechanism.

🏏

Cricket analogy: Just as some franchises stick with the traditional red-ball domestic pathway to develop players while others use T20 academies, teams that already invest in JUnit for unit testing extend that same investment to Selenium rather than adopting a separate framework like TestNG.

JUnit 5 Lifecycle and the Extension Model

@BeforeEach and @AfterEach run before and after every @Test method (equivalent to TestNG's @BeforeMethod/@AfterMethod), while @BeforeAll and @AfterAll run once per test class and must be static unless the class uses @TestInstance(Lifecycle.PER_CLASS). JUnit 5's real architectural advantage is @ExtendWith, which plugs in reusable Extension classes — a common Selenium pattern is a custom WebDriverExtension implementing BeforeEachCallback and AfterEachCallback to inject a managed WebDriver instance via ParameterResolver, so test methods simply declare a WebDriver parameter and never touch driver creation code directly.

🏏

Cricket analogy: A modern franchise doesn't build its own fitness program from scratch each season — it plugs in a specialist strength-and-conditioning consultant (an extension) who handles that concern independently; @ExtendWith plugs a WebDriverExtension into JUnit the same modular way.

java
// JUnit 5 Selenium example
import org.junit.jupiter.api.*;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.By;

import static org.junit.jupiter.api.Assertions.*;

@Tag("smoke")
class LoginJUnitTest {
    private WebDriver driver;

    @BeforeEach
    void setUp() {
        driver = new ChromeDriver();
        driver.get("https://example.com/login");
    }

    @Test
    @DisplayName("Valid login redirects to dashboard")
    void loginWithValidCredentials() {
        driver.findElement(By.id("username")).sendKeys("qa_user");
        driver.findElement(By.id("password")).sendKeys("Secr3t!");
        driver.findElement(By.id("loginBtn")).click();

        assertAll("post-login state",
            () -> assertTrue(driver.getCurrentUrl().contains("/dashboard")),
            () -> assertEquals("Welcome, qa_user",
                    driver.findElement(By.cssSelector("h1.welcome")).getText())
        );
    }

    @AfterEach
    void tearDown() {
        if (driver != null) driver.quit();
    }
}

JUnit 4 and JUnit 5 (Jupiter) use different packages and are NOT interchangeable: org.junit.Test (JUnit 4) versus org.junit.jupiter.api.Test (JUnit 5). Mixing them in the same class silently produces tests that don't run under the expected runner. If you're on JUnit 4, use @Rule with a WatchMan or ExternalResource for driver management instead of @ExtendWith, which is JUnit 5 only.

Grouping and Reporting with JUnit and Maven

JUnit 5 groups tests using @Tag (e.g., @Tag("smoke")), and the Maven Surefire or Failsafe plugin's <groups> configuration filters which tags run in a given build phase — smoke tags in the fast unit-test phase, and a broader regression tag in a separate integration-test phase against real browsers. Where TestNG bakes reporting in, JUnit 5 relies on the build tool: Surefire produces XML reports Jenkins can parse, and third-party libraries like Allure JUnit5 add rich HTML dashboards with screenshots, matching the reporting depth TestNG gives out of the box.

🏏

Cricket analogy: A domestic season is split into a red-ball Ranji phase and a white-ball Vijay Hazare phase, each selecting different squads; Maven's Surefire groups filtering smoke vs regression tags is that same phase-based squad selection.

  • JUnit 5 (Jupiter) uses @BeforeEach/@AfterEach and @BeforeAll/@AfterAll, functionally equivalent to TestNG's @BeforeMethod/@AfterMethod and @BeforeClass/@AfterClass.
  • @ExtendWith plus a custom Extension (e.g., implementing BeforeEachCallback and ParameterResolver) is the idiomatic way to inject a managed WebDriver into JUnit 5 tests.
  • assertAll() groups multiple assertions so all of them run and report together instead of stopping at the first failure.
  • JUnit 4 (org.junit) and JUnit 5 (org.junit.jupiter.api) are different APIs and must not be mixed in the same test class.
  • @Tag replaces TestNG's groups for categorizing tests (smoke, regression) and is filtered via Maven Surefire/Failsafe configuration.
  • JUnit 5 has no built-in HTML report like TestNG; teams typically add Allure or rely on Surefire's XML plus CI parsing.
  • Choose JUnit over TestNG mainly when a Java codebase is already standardized on JUnit for unit tests, for tooling consistency.

Practice what you learned

Was this page helpful?

Topics covered

#Testing#SeleniumStudyNotes#TestingQA#SeleniumWithJUnit#Selenium#JUnit#Lifecycle#Extension#StudyNotes#SkillVeris