ConfNG

Configuration Management for TestNG Projects

Built for TestNG with extensible support for other Java applications. Simplify loading and resolving configuration values from multiple sources with precedence-based resolution, type safety, and automatic TestNG parameter injection.

// Define configuration keys
public enum TestConfig implements ConfNGKey {
    BROWSER("browser"),
    BASE_URL("base.url"),
    TIMEOUT("timeout");
    
    // Implementation...
}

// Built for TestNG projects with extensible Java support
// TestNG parameters automatically injected via service loader

// Load configuration sources
ConfNG.loadProperties("test.properties");
ConfNG.loadJson("config.json");

// TestNG projects: testng.xml parameters are automatically available:
// <parameter name="browser" value="firefox"/>
// <parameter name="base.url" value="https://staging.example.com"/>

// Use in TestNG tests or other Java applications
@Test
public void testConfiguration() {
    String browser = ConfNG.get(TestConfig.BROWSER);     // From testng.xml or other sources
    Integer timeout = ConfNG.getInt(TestConfig.TIMEOUT); // Type-safe conversion
    // Your test logic...
}

Why Choose ConfNG?

๐Ÿ”ง

Multiple Sources

Environment variables, system properties, properties files, JSON files, custom sources, and automatic TestNG parameter injection with configurable precedence.

๐Ÿ›ก๏ธ

Type Safety

Enum-based configuration keys with compile-time checking and automatic type conversion for integers and booleans.

๐Ÿš€

High Performance

Eager resolution of configuration values during initialization saves resources and improves runtime performance.

๐Ÿ”

Auto-discovery

Automatic scanning for configuration keys using reflection with support for custom package filtering.

๐Ÿ”

Secret Management

Built-in support for secret managers like AWS Secrets Manager and HashiCorp Vault with caching and error handling.

๐Ÿงฉ

Extensible

Easy to add custom configuration sources and integrate with existing systems through clean interfaces.

๐Ÿงช

TestNG-First Design

Built specifically for TestNG projects with zero-configuration parameter injection that automatically captures and injects all parameters from testng.xml, with extensible support for other Java applications.

Quick Start

1

Add Dependency

dependencies {
    implementation 'org.confng:confng:1.0.1'
}
<dependency>
    <groupId>org.confng</groupId>
    <artifactId>confng</artifactId>
    <version>1.0.1</version>
</dependency>
2

Define Configuration Keys

import org.confng.api.ConfNGKey;

public enum TestConfig implements ConfNGKey {
    BROWSER("browser", "chrome"),
    BASE_URL("base.url", "http://localhost:8080"),
    TIMEOUT("timeout", "30"),
    HEADLESS("headless", "false");
    
    private final String key;
    private final String defaultValue;
    
    TestConfig(String key, String defaultValue) {
        this.key = key;
        this.defaultValue = defaultValue;
    }
    
    @Override
    public String getKey() {
        return key;
    }
    
    @Override
    public String getDefaultValue() {
        return defaultValue;
    }
}
3

Load Configuration Sources

import org.confng.ConfNG;

public class TestConfig {
    static {
        // Built for TestNG projects, extensible for other Java applications
        // TestNG parameters are automatically injected when TestNG is present
        
        // Load configuration files (optional - skipped if not found)
        ConfNG.loadProperties("test.properties");
        ConfNG.loadJson("config.json");
        
        // Add custom sources if needed
        ConfNG.registerSource(new CustomConfigSource());
    }
}
4

Use in TestNG Tests

// Primary use case: TestNG test projects

@Test
public void testWebApplication() {
    // TestNG parameters from testng.xml are automatically available!
    // No listener registration or manual setup required
    
    // Get configuration values with type safety
    String browser = ConfNG.get(TestConfig.BROWSER);     // From testng.xml or other sources
    String baseUrl = ConfNG.get(TestConfig.BASE_URL);    // From testng.xml or other sources
    Integer timeout = ConfNG.getInt(TestConfig.TIMEOUT); // From testng.xml or other sources
    Boolean headless = ConfNG.getBoolean(TestConfig.HEADLESS);
    
    // Use configuration in your tests
    WebDriver driver = createDriver(browser, headless);
    driver.manage().timeouts().implicitlyWait(timeout, TimeUnit.SECONDS);
    driver.get(baseUrl);
}

// Also works in other Java applications
public class DatabaseService {
    public void connect() {
        String dbUrl = ConfNG.get(AppConfig.DATABASE_URL);
        String apiKey = ConfNG.get(AppConfig.API_KEY);
        // Your application logic...
    }
}
โœจ

TestNG-First with Extensible Support

ConfNG is built for TestNG projects with extensible support for other Java applications:

  • โœ… TestNG-First: Designed specifically for TestNG test projects
  • โœ… Automatic Detection: Detects TestNG on classpath and activates features
  • โœ… Zero Configuration: Registers parameter injection listener via service loader
  • โœ… Parameter Capture: Captures all testng.xml parameters (suite, test, method levels)
  • โœ… Smart Precedence: Handles parameter precedence (method > test > suite)
  • โœ… Thread-Safe: Concurrent test execution support
  • โœ… Extensible: Can be used in other Java applications when needed

Built for TestNG, extensible for more!

Documentation

๐Ÿ“š User Guide

Complete guide covering all features, configuration sources, and advanced usage patterns.

Read Guide

๐Ÿ”ง API Reference

Detailed API documentation with all classes, methods, and configuration options.

View API

๐Ÿ’ก Examples

Working examples and code samples for common use cases and integrations.

See Examples

Examples

Basic Configuration Usage

// Configuration files
// test.properties
browser=chrome
base.url=https://staging.example.com
timeout=30

// config.json
{
  "browser": "firefox",
  "base.url": "https://prod.example.com",
  "timeout": 45
}

// Java code - primarily for TestNG projects
public enum TestConfig implements ConfNGKey {
    BROWSER("browser", "chrome"),
    BASE_URL("base.url", "http://localhost"),
    TIMEOUT("timeout", "30");
    
    // Constructor and methods...
}

// In TestNG tests
@BeforeClass
public void setup() {
    ConfNG.loadProperties("test.properties");
    ConfNG.loadJson("config.json");
}

@Test
public void testApplication() {
    String browser = ConfNG.get(TestConfig.BROWSER);
    String url = ConfNG.get(TestConfig.BASE_URL);
    Integer timeout = ConfNG.getInt(TestConfig.TIMEOUT);
    
    // Precedence: Env > System Props > TestNG Params > Properties > JSON
    // If BROWSER env var is set, it overrides file values
    
    WebDriver driver = createDriver(browser);
    driver.get(url);
}

// Also works in other Java applications
public class ConfigService {
    public void loadConfig() {
        ConfNG.loadProperties("app.properties");
        String value = ConfNG.get(AppConfig.SOME_VALUE);
        // Use configuration...
    }
}

Secret Manager Integration

// Custom AWS Secrets Manager integration
public class AWSSecretsSource extends SecretManagerSource {
    private final SecretsManagerClient client;
    
    public AWSSecretsSource() {
        super(300000); // 5 minute cache timeout
        this.client = SecretsManagerClient.builder()
            .region(Region.US_EAST_1)
            .build();
    }
    
    @Override
    public String getName() {
        return "AWSSecretsManager";
    }
    
    @Override
    protected String fetchSecret(String secretId) throws Exception {
        GetSecretValueRequest request = GetSecretValueRequest.builder()
            .secretId(secretId)
            .build();
        
        GetSecretValueResponse response = client.getSecretValue(request);
        return response.secretString();
    }
}

// Usage
AWSSecretsSource secretSource = new AWSSecretsSource();
secretSource.addKeyMapping("db.password", "prod/database/password");
secretSource.addKeyMapping("api.key", "prod/external-api/key");
ConfNG.loadSecretSource(secretSource);

// In tests
String dbPassword = ConfNG.get(DatabaseConfig.PASSWORD);
String apiKey = ConfNG.get(ApiConfig.KEY);

Custom Configuration Sources

// Custom database configuration source
public class DatabaseConfigSource implements ConfigSource {
    private final Map<String, String> configCache = new HashMap<>();
    private final DataSource dataSource;
    
    public DatabaseConfigSource(DataSource dataSource) {
        this.dataSource = dataSource;
        loadConfigurations();
    }
    
    @Override
    public String getName() {
        return "DatabaseConfig";
    }
    
    @Override
    public Optional<String> get(String key) {
        return Optional.ofNullable(configCache.get(key));
    }
    
    private void loadConfigurations() {
        try (Connection conn = dataSource.getConnection()) {
            PreparedStatement stmt = conn.prepareStatement(
                "SELECT config_key, config_value FROM app_config WHERE active = true"
            );
            ResultSet rs = stmt.executeQuery();
            
            while (rs.next()) {
                configCache.put(rs.getString("config_key"), rs.getString("config_value"));
            }
        } catch (SQLException e) {
            throw new RuntimeException("Failed to load database configuration", e);
        }
    }
}

// Register the custom source
ConfNG.registerSource(new DatabaseConfigSource(dataSource));

TestNG Integration Features

// ConfNG is built for TestNG projects!
// When TestNG is detected on classpath, automatic features activate

// testng.xml example:
// <suite name="Test-Suite">
//     <parameter name="browser" value="chrome"/>
//     <parameter name="base.url" value="https://staging.example.com"/>
//     <test name="Smoke-Tests">
//         <parameter name="browser" value="firefox"/> <!-- Overrides suite level -->
//         <parameter name="timeout" value="45"/>
//         <classes><class name="com.example.SmokeTest"/></classes>
//     </test>
//     <test name="Regression-Tests">
//         <parameter name="browser" value="edge"/>
//         <classes><class name="com.example.RegressionTest"/></classes>
//     </test>
// </suite>

// Configuration enum
public enum TestConfig implements ConfNGKey {
    BROWSER("browser", "chrome"),
    BASE_URL("base.url", "http://localhost:8080"),
    TIMEOUT("timeout", "30");
    
    // Standard implementation...
}

// TestNG test class - automatic parameter injection!
public class SmokeTest {
    
    @Test
    public void testAutomaticParameterInjection() {
        // โœจ TestNG feature: parameters automatically injected!
        // Zero configuration - ConfNG detects TestNG and activates listener
        
        String browser = ConfNG.get(TestConfig.BROWSER);     // "firefox" (from test level)
        String baseUrl = ConfNG.get(TestConfig.BASE_URL);    // "https://staging.example.com" (from suite)
        Integer timeout = ConfNG.getInt(TestConfig.TIMEOUT); // 45 (from test level)
        
        System.out.println("Browser: " + browser);   // firefox
        System.out.println("Base URL: " + baseUrl);  // https://staging.example.com
        System.out.println("Timeout: " + timeout);   // 45
        
        // TestNG precedence: Method > Test > Suite > Other sources
    }
    
    @Test
    public void testMixedSources() {
        // TestNG parameters work alongside other sources
        ConfNG.loadProperties("test.properties");
        
        // TestNG parameters have high precedence (priority 80)
        // They override properties files but not env vars or system props
        String browser = ConfNG.get(TestConfig.BROWSER);
        
        // Use in Selenium tests, API tests, etc.
        WebDriver driver = WebDriverFactory.create(browser);
        // Test implementation...
    }
}

// Extensible: works in other Java applications too
public class DatabaseService {
    public void connect() {
        // Same ConfNG API, no TestNG features (since TestNG not present)
        ConfNG.loadProperties("app.properties");
        
        String dbUrl = ConfNG.get(AppConfig.DATABASE_URL);
        // Your application logic...
    }
}