How to Use FrameworkConstants for Centralized Configuration Management in anhtester/automationframeworkselenium

FrameworkConstants provides a single source of truth for all configuration values by loading properties from external files once at class initialization and exposing them as public static final fields across the entire Selenium automation framework.

The anhtester/automationframeworkselenium repository implements a robust design pattern for managing test configuration through the FrameworkConstants class. This centralized approach eliminates hard-coded values from test scripts and ensures that environment-specific settings can be modified without changing source code. By leveraging static initialization and property file loading, the framework achieves both type safety and runtime flexibility.

Understanding FrameworkConstants Architecture

FrameworkConstants acts as the centralized configuration hub located at src/main/java/com/anhtester/constants/FrameworkConstants.java. Rather than scattering configuration logic throughout test classes, this class consolidates every environment variable, URL, credential, and execution flag into publicly accessible static constants. The design follows the Single Point of Truth principle, ensuring that changing a value in one location propagates to all consuming components immediately.

Loading Configuration at Runtime

The framework initializes constants through a lazy-loading mechanism that reads property files exactly once during class loading. This process involves two critical components working in tandem.

PropertiesHelpers.loadAllFiles() handles the initial I/O operations by reading config.properties, data.properties, and crm_locators.properties from the resources directory. This method merges all key-value pairs into a single java.util.Properties instance and executes within a static block in FrameworkConstants, guaranteeing one-time execution per JVM lifecycle.

Individual constants then call PropertiesHelpers.getValue(key) to retrieve their assigned values. For example, the browser configuration resolves through public static final String BROWSER = PropertiesHelpers.getValue("BROWSER");. Because these fields are static final, they remain immutable after initialization while remaining globally accessible to any class in the test suite.

Practical Implementation Examples

The following patterns demonstrate how various framework components consume these centralized constants to maintain clean, maintainable code.

Accessing URLs and Browser Settings in Tests

Test classes reference constants directly when initializing test environments, removing the need for hard-coded strings.

import com.anhtester.constants.FrameworkConstants;

// Navigate to the CRM application using centralized configuration
WebUI.openWebsite(FrameworkConstants.URL_CRM);

This pattern allows QA engineers to switch between staging, production, or local environments by simply updating the URL_CRM value in src/test/resources/config/config.properties without touching test logic.

Configuring Driver Factories for Remote Execution

The TargetFactory class at src/main/java/com/anhtester/driver/TargetFactory.java uses multiple constants to determine execution strategy and browser capabilities.

import com.anhtester.constants.FrameworkConstants;
import com.anhtester.driver.BrowserFactory;

public class TargetFactory {
    public static WebDriver createDriver() {
        // Resolve browser type from centralized constant
        BrowserFactory browserFactory = BrowserFactory.valueOf(FrameworkConstants.BROWSER.toUpperCase());
        
        // Check execution target (local vs remote)
        if (FrameworkConstants.TARGET.equalsIgnoreCase("remote")) {
            return new RemoteWebDriver(
                new URL(FrameworkConstants.REMOTE_URL + ":" + FrameworkConstants.REMOTE_PORT), 
                browserFactory.getOptions()
            );
        }
        return browserFactory.createDriver(); // Local execution
    }
}

Integrating with Reporting Systems

Reporting utilities leverage constants for consistent configuration across Extent Reports, Allure, and optional Telegram notifications.

import com.anhtester.constants.FrameworkConstants;
import com.anhtester.reports.ExtentReportManager;

// Initialize reporting with centralized title configuration
ExtentReportManager.startReport(FrameworkConstants.REPORT_TITLE);

Similarly, TelegramManager at src/main/java/com/anhtester/reports/TelegramManager.java accesses webhook URLs and authentication tokens through the same constant interface, ensuring sensitive data remains out of source control while remaining accessible to the framework.

Controlling Execution Modes

The base test class at src/test/java/com/anhtester/common/BaseTest.java demonstrates conditional logic using boolean-like string constants.

if (FrameworkConstants.HEADLESS.equalsIgnoreCase("true")) {
    ChromeOptions options = new ChromeOptions();
    options.addArguments("--headless");
    // Additional headless configuration...
}

This approach enables CI/CD pipelines to toggle headless mode, video recording, or report archiving through external property files rather than code changes.

Extending the Configuration System

Adding new configuration parameters requires minimal changes across three files. First, add the key-value pair to src/test/resources/config/config.properties. Next, expose the value in FrameworkConstants by declaring a new static field: public static final String MY_NEW_SETTING = PropertiesHelpers.getValue("MY_NEW_SETTING");. Finally, reference FrameworkConstants.MY_NEW_SETTING throughout the codebase. Because the PropertiesHelpers cache loads during initial class access, new constants become immediately available without modifying loading logic.

Summary

  • FrameworkConstants at src/main/java/com/anhtester/constants/FrameworkConstants.java provides immutable, globally accessible configuration values as public static final fields.
  • PropertiesHelpers loads config.properties, data.properties, and locator files exactly once during static initialization, eliminating repetitive I/O operations.
  • Driver factories, reporting managers, and test classes reference these constants directly, keeping implementation code free of hard-coded environment details.
  • The architecture supports seamless environment switching and feature toggling through external property files without requiring code recompilation.
  • Extending the system involves adding keys to property files and corresponding static fields in FrameworkConstants.

Frequently Asked Questions

Where does FrameworkConstants load its values from?

FrameworkConstants loads values from three property files located in src/test/resources/config/: config.properties for environment settings, data.properties for test data, and crm_locators.properties for element locators. The PropertiesHelpers.loadAllFiles() method merges these into a single Properties object during class initialization.

Can I modify configuration values during test execution?

No, constants are declared as public static final, making them immutable after the static initialization block completes. If you need dynamic configuration changes during runtime, you must interact with PropertiesHelpers directly rather than using the constant fields, though this pattern is discouraged as it breaks the centralized design.

How do I add a new configuration parameter to the framework?

Add your key-value pair to src/test/resources/config/config.properties, then declare a corresponding field in FrameworkConstants using PropertiesHelpers.getValue("YOUR_KEY"). The new constant becomes available immediately to all classes importing FrameworkConstants without requiring changes to the loading mechanism.

Why use static final fields instead of direct Properties access?

Static final fields provide compile-time type safety, IDE autocomplete support, and refactoring capabilities that raw Properties objects lack. Additionally, this pattern prevents typos in property keys and ensures that configuration is read exactly once, improving performance by avoiding repeated file system access during test execution.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →