@Before Hook in Cucumber JVM
What Is the @Before Hook?
The @Before hook is a Cucumber lifecycle hook that executes automatically before a scenario starts. It runs before the first Gherkin step of every applicable scenario and is primarily used to prepare the test environment. In a Cucumber JVM framework, this preparation may include launching the browser, initializing WebDriver, reading configuration files, opening the application, connecting to a database, configuring API clients, creating test data, clearing browser state, and starting reporting.
In simple terms, @Before runs before the first step of a scenario. Unlike step definitions, it is not written in the feature file. There is no Gherkin sentence that directly calls it. Cucumber discovers the method through the @Before annotation and invokes it automatically as part of the scenario lifecycle. This is what makes it useful for setup code that should run consistently without cluttering feature files.
The main purpose of the @Before hook is to ensure that every scenario begins from a known and predictable state. A scenario should not depend on leftover browser sessions, old cookies, uninitialized drivers, missing configuration, disconnected databases, or manually created setup. The hook gives the framework a reliable entry point before business steps begin. When used correctly, it makes tests cleaner, more repeatable, and easier to maintain.
The @Before hook is part of framework infrastructure, not business behavior. It should prepare the environment so the scenario can run. It should not secretly perform the main business workflow of the scenario. This distinction is important. If a hook logs in, searches for a product, adds it to the cart, and completes payment, the feature file no longer shows what the scenario actually does. Good hooks keep technical setup outside Gherkin, but they do not hide meaningful business behavior.
Why the @Before Hook Is Needed
Almost every automation test needs some setup before execution. A Selenium scenario needs a browser and WebDriver. An API scenario needs a base URI, authentication, headers, or request defaults. A database scenario may need a connection. A reporting framework may need a new test entry. A scenario that uses fresh customer data may need that customer created before the first step. Without a @Before hook, setup code is often repeated in feature files or step definitions.
Repeated setup creates several problems. Feature files become longer than necessary. Business behavior becomes mixed with technical instructions. Step definitions duplicate the same initialization code. Maintenance becomes harder because a setup change must be made in many places. For example, if every scenario contains a step for launching the browser and opening the application, every scenario becomes noisy. Browser launch is not the business rule being tested; it is a framework requirement.
Scenario: Login
Given browser is launched
And application is opened
When user logs in
Then dashboard should appear
Scenario: Search
Given browser is launched
And application is opened
When user searches product
Then products should appear
Both scenarios repeat the same setup. This violates the DRY principle and reduces readability. With @Before, the setup becomes automatic, and the feature file can focus on the behavior that matters.
Scenario: Login
When user logs in
Then dashboard should appear
@Before
public void setup() {
// launch browser
// open application
}
The result is cleaner Gherkin and centralized setup. If browser setup changes, the hook or helper class changes in one place. The scenarios do not need to change because they never described the technical setup directly.
Execution Flow of the @Before Hook
The @Before hook executes after Cucumber selects the scenario and before the first step definition runs. If the project also has an @After hook, the typical scenario lifecycle is: start scenario, run @Before, execute steps, run @After, and end scenario. This flow happens for every applicable scenario.
Start Scenario
|
v
@Before Hook
|
v
First Step
|
v
Remaining Steps
|
v
@After Hook
This order is important because step definitions often depend on setup done by the hook. If the hook initializes WebDriver, page objects can use the driver during steps. If the hook loads configuration, services can read URLs, credentials, or timeouts. If the hook creates test data, the scenario can use that data in the first business action. The hook creates the baseline.
If the @Before hook fails, the scenario should not continue as if setup succeeded. Continuing with a partially initialized environment leads to confusing failures. For example, if WebDriver initialization fails but the first step attempts to click a button, the error may appear as a null driver issue rather than a setup failure. Good hook code logs setup problems clearly and lets the scenario fail fast.
Basic Syntax of the @Before Hook
The basic syntax is simple. Import the Cucumber Before annotation, create a public method, return void, and annotate the method with @Before. The method usually has no parameters, although many Cucumber JVM setups allow the Scenario object to be injected when scenario metadata is needed.
import io.cucumber.java.Before;
public class Hooks {
@Before
public void setup() {
System.out.println("Launching Browser");
}
}
When a scenario runs, Cucumber prints the message before executing the scenario steps. The method name can be anything meaningful, such as setup, initializeDriver, apiSetup, or beforeScenario. The annotation is what makes it a hook.
The hook class must be located in a package scanned by Cucumber glue. If the hook method is correct but Cucumber does not discover it, check the glue configuration in the runner or platform setup. This is a common issue when hooks are placed in a separate package that is not included in the glue path.
Selenium Setup with @Before
In Selenium automation, the most common use of @Before is WebDriver setup. The hook creates a browser driver, maximizes the window, applies configuration, and opens the application URL. This ensures every scenario starts with a fresh browser session unless the framework intentionally uses a different browser lifecycle.
@Before
public void setup() {
driver = new ChromeDriver();
driver.manage().window().maximize();
driver.get("https://example.com");
}
This example is easy to understand, but production frameworks usually delegate driver setup to a factory class. A hook with direct new ChromeDriver() may be fine for a small practice project, but real frameworks often need browser selection, headless mode, remote grid execution, download preferences, window size, timeouts, and environment URLs. Putting all of that directly in the hook makes the hook large and hard to maintain.
@Before
public void setup() {
DriverFactory.initialize();
DriverFactory.getDriver().get(ConfigReader.getUrl());
}
This version keeps the hook short. DriverFactory handles driver creation. ConfigReader supplies the URL. The hook coordinates setup rather than containing every detail. This is the preferred direction for scalable Selenium Cucumber frameworks.
API Testing Setup with @Before
In API automation, a @Before hook can configure shared request settings. It may set the Rest Assured base URI, load authentication tokens, prepare headers, initialize request specifications, or start API logging. This avoids repeating the same API configuration in every step definition.
@Before
public void apiSetup() {
RestAssured.baseURI = "https://api.example.com";
}
In a mature framework, the hook may delegate to an API client setup class. That class can read the environment, configure base paths, attach headers, and prepare authentication. The hook only triggers the setup. This keeps API step definitions focused on business operations such as creating users, submitting orders, or validating responses.
Tagged hooks are especially useful for API setup. If the same project contains UI and API scenarios, there is no reason to configure API clients for pure UI scenarios unless those scenarios need backend setup. A tagged @Before("@API") hook can apply API setup only when required.
Database Setup with @Before
Some scenarios need database access for setup, validation, or cleanup. A @Before hook can establish a database connection before those scenarios run. This is cleaner than opening a connection inside every step definition that needs one.
@Before
public void databaseSetup() {
database.connect();
}
Database setup should be scoped carefully. Opening a database connection before every scenario wastes resources if most scenarios do not need database access. A tagged hook such as @Before("@DB") can restrict database setup to scenarios that actually require it. This improves performance and reduces unnecessary dependency on the database.
Database hooks should also consider connection cleanup. If a connection is opened in @Before, it should usually be closed in @After. Setup and teardown should be designed together so resources are not leaked.
Configuration Loading with @Before
Configuration values are often needed before a scenario starts. Browser name, base URL, environment, timeout values, API endpoints, grid URL, and report settings may all come from configuration files, environment variables, or CI/CD parameters. A @Before hook can trigger configuration loading so the rest of the framework can use these values consistently.
@Before
public void loadConfiguration() {
ConfigReader.loadProperties();
}
Configuration should be loaded once when possible, not repeatedly in expensive ways before every scenario. Some frameworks load configuration in a static initializer or test runner setup. Others use a hook. The right approach depends on the framework. If configuration loading is placed in @Before, make sure it is efficient and idempotent.
A hook should not hardcode values such as driver.get("https://testsite.com") when the framework supports multiple environments. Reading from configuration keeps the same automation code usable across QA, UAT, staging, and local execution.
Report Initialization with @Before
Reporting frameworks often need a new test entry before scenario execution begins. A @Before hook can start reporting, attach scenario names, capture tags, or initialize logging context. This gives each scenario a clear reporting container before steps run.
@Before
public void reportSetup() {
reportManager.startTest();
}
If the hook receives a Scenario object, it can use the scenario name and tags to create a more meaningful report entry. This can help organize results by feature, tag, browser, environment, or execution type. Reporting logic should still be delegated to a report manager so the hook remains small.
Reporting setup should be paired with report finalization in @After. Starting a report entry without closing or flushing it can produce incomplete reports. Hooks provide both lifecycle points, so reporting should use them as a pair.
Test Data Creation with @Before
Some scenarios require fresh test data before the first step executes. A @Before hook can create a customer, user, order, token, or other prerequisite data. This is useful when many scenarios with a specific tag need the same kind of setup. For example, scenarios tagged @RequiresCustomer may need a new customer created before execution.
@Before("@RequiresCustomer")
public void createTestData() {
customer = customerService.createCustomer();
}
Be careful with test data creation in hooks. If the created data is important to understanding the scenario, hiding it in a hook may reduce feature file clarity. A hook is appropriate when the data is technical setup or a common prerequisite. If the data is central to the business rule, it may be better expressed in a Gherkin step such as Given a new customer exists.
Any data created in @Before should usually be cleaned in @After. Store identifiers immediately so cleanup can target the correct records. Setup and cleanup must work together to keep environments stable.
Clearing Browser State with @Before
Browser state can affect test independence. Cookies, local storage, session storage, cache, and prior sessions can change application behavior. A @Before hook can clear cookies or reset state before a scenario starts. This helps each scenario begin from a clean baseline.
@Before
public void clearCookies() {
driver.manage().deleteAllCookies();
}
The exact timing matters. Cookies can only be deleted after the driver exists, and sometimes after a domain has been loaded. If cookie cleanup depends on driver initialization, hook order must be controlled. For deeper cleanup, frameworks may also clear local storage through JavaScript or start each scenario with a fresh browser profile.
Clean browser state is particularly important for login, permissions, cart, and personalization scenarios. If one scenario leaves a user logged in and another scenario expects a logged-out state, failures can become confusing. A @Before hook gives the framework a consistent starting point.
Multiple @Before Hooks
Cucumber allows multiple @Before hooks. A framework may have one hook to read configuration, another to initialize reporting, another to start the driver, and another to prepare test data. Multiple hooks can keep methods focused, but order becomes important when one setup step depends on another.
@Before(order = 1)
public void loadConfiguration() {
}
@Before(order = 2)
public void initializeReports() {
}
@Before(order = 3)
public void browserSetup() {
}
Lower order values execute first for @Before hooks. In the example, configuration loads before reports and browser setup. This is useful because driver setup may need browser and environment values from configuration. Reporting may need scenario or environment metadata.
Use ordering only when needed. If too many hooks depend on a fragile order, the lifecycle becomes hard to reason about. Often the better design is one clear setup hook that delegates to a setup service in the exact sequence required. The hook remains small, and the setup service makes the order explicit.
Tagged @Before Hooks
Tagged @Before hooks run only for scenarios with matching tags. This is one of the most useful hook features because different scenarios often need different setup. UI scenarios need browsers. API scenarios need API clients. Database scenarios need database connections. Smoke scenarios may need lightweight setup. End-to-end scenarios may need more complete environment preparation.
@Smoke
Scenario: Login
When user logs in
Then dashboard should appear
@Before("@Smoke")
public void smokeSetup() {
System.out.println("Smoke Setup");
}
Only scenarios tagged with @Smoke execute this hook. This avoids unnecessary setup for unrelated scenarios. For example, launching a browser before every API scenario wastes time. Opening a database connection for every UI scenario may be unnecessary. Tagged hooks make lifecycle behavior more precise.
Multiple tagged hooks can exist. A scenario with both @UI and @Smoke may trigger both UI setup and smoke-specific setup. This is powerful, but teams should keep tag strategy clean. Too many overlapping tags can make setup difficult to predict. Tags should represent meaningful categories and framework needs.
@Before Hook Versus Step Definition
The @Before hook and step definitions have different responsibilities. A @Before hook runs automatically before applicable scenarios. It is not written in the feature file. It is used for framework setup. A step definition runs only when a matching Gherkin step appears in the scenario. It represents business behavior or scenario-specific action.
If the action is technical preparation needed for execution, it may belong in @Before. If the action is part of the behavior that the scenario communicates, it belongs in a step definition. Launching a browser is setup. Logging in may be business behavior or setup depending on the scenario. Searching for a product, placing an order, and processing payment are business workflows and should not be hidden in a generic @Before hook.
This distinction keeps feature files honest. A reader should be able to understand the behavior being tested by reading the scenario. Hooks should support that execution, not hide meaningful behavior from the reader.
What Should Be Inside a @Before Hook?
A @Before hook should contain environment preparation and framework setup. Good examples include launching the browser, initializing WebDriver, reading configuration, connecting to a database, configuring an API client, initializing reports, creating technical test data, clearing cookies, preparing scenario context, and setting execution metadata.
The hook should be short and should delegate implementation. Instead of placing many lines of driver setup directly in the hook, call DriverFactory.initialize(). Instead of parsing files directly in the hook, call ConfigReader.load(). Instead of building complex data directly in the hook, call TestDataService.createCustomer(). This keeps lifecycle code readable.
Setup should also be deterministic. Every scenario should start in a predictable state. If setup depends on random external conditions, the hook should validate those conditions and fail clearly when they are not met. A failing setup should produce a clear setup error, not a confusing business-step failure later.
What Should Not Be Inside a @Before Hook?
A @Before hook should not contain business workflows, assertions, product searches, order placement, payment processing, long Selenium flows, or scenario-specific behavior that belongs in Gherkin. Hooks prepare the environment; they do not execute the scenario.
@Before
public void setup() {
login();
searchProduct();
purchaseItem();
}
This is a poor design because it hides business behavior from the feature file. If the scenario depends on a purchased item, that context should be visible through a meaningful step or a clearly tagged setup service. Generic hooks should not secretly perform user journeys.
Assertions should also be avoided in @Before hooks unless they validate framework readiness. Business assertions belong in scenario steps. A hook can verify that required configuration exists or that setup completed successfully, but it should not replace Then steps that validate application behavior.
Common Mistakes with @Before Hooks
Putting Business Logic Inside Hooks
The most common mistake is using @Before to perform real business workflows. This makes feature files misleading. Keep hooks focused on setup and leave business behavior in steps.
Creating Large Hook Methods
A hook with hundreds of lines is difficult to maintain. Break setup into helper classes such as driver factories, configuration loaders, report managers, API clients, and test data services.
Hardcoding Values
Hardcoding URLs, browsers, credentials, or environment values inside hooks reduces flexibility. Read values from configuration, environment variables, or secure stores instead.
Using Thread.sleep()
Hard waits in setup slow the suite and make timing unreliable. Use proper synchronization, readiness checks, API health checks, or explicit waits where needed.
Ignoring Setup Exceptions
If setup fails, the scenario should fail clearly. Do not swallow exceptions and continue with a partially initialized environment. Log the issue and let the failure point to setup.
Best Practices for @Before Hooks
Use @Before only for environment preparation. Keep hook methods short and delegate implementation to utility or service classes. Use the order attribute when multiple hooks must execute in a specific sequence. Use tagged hooks for scenario-specific setup so unnecessary setup does not run for every scenario.
Avoid business logic and assertions inside hooks. Read configuration instead of hardcoding values. Ensure every scenario starts from a clean and consistent state. Pair setup with teardown: if @Before creates a driver, opens a database connection, starts a report entry, or creates temporary data, an appropriate @After hook should close, disconnect, flush, or clean it.
Design hooks for parallel execution. Avoid unsafe static state. Use scenario-level context, dependency injection, or thread-safe factories when tests run in parallel. A setup hook that works in single-thread execution may fail under parallel execution if it stores driver or data in shared variables.
Real-Time Framework Example
A practical Cucumber JVM framework may keep hooks, utilities, page objects, and step definitions in separate packages. The hook class coordinates setup, while utilities handle the details. This structure keeps lifecycle code centralized and reusable.
src
├── hooks
│ └── Hooks.java
├── utils
│ ├── DriverFactory.java
│ └── ConfigReader.java
├── pages
│ └── LoginPage.java
└── stepdefinitions
└── LoginSteps.java
public class Hooks {
@Before(order = 1)
public void loadConfiguration() {
ConfigReader.load();
}
@Before(order = 2)
public void initializeDriver() {
DriverFactory.initialize();
}
}
The execution flow is predictable. Cucumber starts the scenario, loads configuration, initializes the driver, and then executes the first Gherkin step. Step definitions can assume the framework is ready. The feature file remains focused on business behavior.
Using the Scenario Object in @Before
In many Cucumber JVM projects, the @Before hook can receive a Scenario object. This object gives access to scenario metadata such as the scenario name and tags. It is useful when the setup needs to initialize reporting, logging, or scenario context with meaningful information before the first step runs. For example, a report manager may create a test entry using the scenario name, while a logger may include the scenario name in every log line for that execution.
@Before
public void beforeScenario(Scenario scenario) {
reportManager.startTest(scenario.getName());
}
The Scenario object should be used for lifecycle metadata, not for hidden business decisions. It is fine to use tags or scenario names to create report labels, initialize context, or decide whether framework setup applies. It is not a good idea to use scenario names to run secret business workflows. If a business precondition matters, it should be visible in the feature file or represented through a clear tagged setup strategy.
Using the Scenario object is also helpful for debugging setup failures. If driver creation fails, the setup log can include the scenario name and tags. This makes it easier to identify which scenario failed during setup, especially when running large suites in parallel. Clear setup logs save time because failures before the first step can otherwise look vague.
Designing @Before for Parallel Execution
Parallel execution changes how @Before hooks should be designed. In single-thread execution, unsafe shared state may not fail immediately. In parallel execution, it can cause random and difficult failures. For example, if a hook stores WebDriver in one global static variable and several scenarios run at the same time, one scenario may overwrite another scenario's driver. The result can be browser actions happening in the wrong session or drivers closing while another scenario still needs them.
A parallel-safe @Before strategy uses scenario-level or thread-safe storage. Many frameworks use ThreadLocal for WebDriver, dependency injection for scenario-scoped objects, or a scenario context object that belongs only to the current scenario. The exact pattern depends on the project, but the principle is the same: setup data created for one scenario should not leak into another scenario.
@Before("@UI")
public void initializeUiScenario() {
DriverFactory.initializeForCurrentThread();
}
Parallel setup also affects test data. If a @Before hook creates users, customers, or records, those records should be unique to the scenario or thread. Shared mutable data causes collisions. A setup hook that creates testuser@example.com for every parallel scenario will quickly fail. A better strategy includes a run ID, thread ID, timestamp, or UUID in generated values and stores the created identifiers for cleanup.
Handling @Before Setup Failures
Setup failures should be treated seriously because the scenario cannot run correctly without a valid starting state. If browser initialization fails, API configuration is missing, a database connection cannot be opened, or required test data cannot be created, the framework should fail early with a clear message. Continuing after setup failure usually creates misleading errors in later steps.
A good @Before hook logs enough context to diagnose the problem. The log should explain what setup operation failed, which scenario was starting, which environment was used, and which configuration values were relevant without exposing secrets. If the failure is caused by missing configuration, say that clearly. If the browser binary or driver is unavailable, say that clearly. If test data creation failed because an API returned an error, include the response details where safe.
Setup hooks should avoid swallowing exceptions. Catching an exception only to print a message and continue is a bad practice. The scenario should not proceed with a null driver, missing token, or broken database connection. If cleanup is needed for partial setup, the framework can perform that cleanup and then rethrow the exception so the scenario is marked failed. This keeps failure reporting honest.
Interview-Ready Explanation
The @Before hook is a Cucumber lifecycle hook that executes automatically before every applicable scenario. It is mainly used for setup tasks such as browser initialization, configuration loading, database connection, API client setup, report initialization, cookie cleanup, and test data creation. It is not referenced in the feature file because Cucumber invokes it automatically before scenario steps run.
Multiple @Before hooks are supported, and their execution order can be controlled with the order attribute. Tagged @Before hooks allow setup to run only for specific scenarios. The best practice is to keep hooks lightweight, delegate complex work to helper classes, avoid business logic and assertions, and ensure every scenario starts in a clean and predictable state.
Summary
The @Before hook is one of the most important setup mechanisms in Cucumber JVM. It allows common preparation tasks to run automatically before scenarios, keeping feature files clean and reducing duplicate setup code. It is useful for Selenium setup, API configuration, database connections, report initialization, browser state cleanup, and test data preparation.
The golden rules are clear: @Before prepares the environment, it does not execute business behavior; every scenario should start in a clean and predictable state; hook methods should stay small and delegate complex work; order should be used when deterministic setup is required; and tagged hooks should be used when setup applies only to specific scenario categories. When designed well, @Before hooks make Cucumber frameworks cleaner, faster, and easier to maintain.