There are several robust strategies for storing and selecting configurations - from "custom layer" (like here) to ready-made libraries. The example below doesn't use third-party libraries and is simple enough to understand.
package common.configs;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class Config {
private static final Config INSTANCE = new Config();
private final Properties properties = new Properties();
private Config() {
try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("config.properties")) {
if (inputStream == null) {
throw new RuntimeException("config.properties is not found in resources");
}
properties.load(inputStream);
} catch (IOException e) {
throw new RuntimeException("Fail to load config.properties", e);
}
}
public static String getProperty(String key) {
String systemValue = System.getProperty(key);
if (systemValue != null) return systemValue;
String envKey = key.toUpperCase().replace(".", "_")The line String envKey = key.toUpperCase().replace(".", "_"); is needed to convert a key from config.properties (e.g., admin.password) to the format accepted for environment variables in OS (e.g., ADMIN_PASSWORD).
Why this is done:
In config.properties keys are usually written in "Java-style" with dots:
admin.password=1234
db.url=jdbc:postgresql://localhost:5432/test
In environment variables in Unix/Windows they usually use uppercase and _ instead of dots:
ADMIN_PASSWORD=1234
DB_URL=jdbc:postgresql://localhost:5432/test
Therefore the method performs transformation:
key.toUpperCase() → admin.password → ADMIN.PASSWORD
.replace(".", "_") → ADMIN_PASSWORD
Thus you get unified logic for value lookup:
first we get from System.getProperty("admin.password") (e.g., if you passed -Dadmin.password=1234 when running Java),
if not found - try from System.getenv("ADMIN_PASSWORD"),
if not there either - get from config.properties.;
String envValue = System.getenv(envKey);
if (envValue != null) return envValue;
return INSTANCE.properties.getProperty(key);
}
}
The Config class implements the Singleton pattern for centralized application configuration management. Key features:
The getProperty() method implements a priority system (highest to lowest):
mvn clean test -DapiBaseUrl=http://localhost
For Docker:
services:
backend:
image: nobugsme/nbank:with_database
environment:
- APIBASEURL=http://localhost:4111
- UIBASEURL=http://localhost:80
- ADMIN_USERNAME=admin
- ADMIN_PASSWORD=admin123
For CI/CD Pipeline:
- name: Run tests
run: ./mvnw clean test -q
env:
UIREMOTE: http://localhost:4444/wd/hub
APIBASEURL: http://194.87.199.75:4111
UIBASEURL: http://194.87.199.75:80
For OS:
# Windows (PowerShell)
$env:APIBASEURL="http://localhost:3000"
$env:ADMIN_USERNAME="admin"
$env:ADMIN_PASSWORD="admin123"
# Linux/macOS (Bash)
export APIBASEURL=http://localhost:3000
export ADMIN_USERNAME=admin
export ADMIN_PASSWORD=admin123
apiBaseUrl=http://localhost:3000
admin.username=admin
admin.password=admin123
common/configs in framework structure
Config.java in it with content from the
example
config.properties in
src/main/resources folder (example provided)
Config.getProperty() method to tests where you need
to get variables from config.properties file (example provided)
# API Configuration
apiBaseUrl=http://localhost:4111
uiBaseUrl=http://localhost
apiVersion=/api/v1
# Browser Configuration
browser=chrome
browserSize=1920x1080
# Admin Credentials
admin.username=admin
admin.password=admin
# Selenoid Configuration
uiRemote=http://localhost:4444/wd/hub
# Database Configuration
db.url=jdbc:postgresql://localhost:5433/nbank
db.username=postgres
db.password=postgres
db.driver=org.postgresql.Driver
db.table.customers=customers
public class BaseUiTest extends BaseApiTest {
@BeforeAll
static void globalSelenideSetup() {
Configuration.remote = Config.getProperty("uiRemote");
Configuration.baseUrl = Config.getProperty("uiBaseUrl");
Configuration.browser = Config.getProperty("browser");
Configuration.browserSize = Config.getProperty("browserSize");
// and so on...
}
}