Sesión 4 de mi lab de Selenium + Java: Dejé de hardcodear, ahora uso config.properties y DriverManager
Eliminar hardcoding del framework. config.properties para URLs y browsers, DriverManager para centralizar el driver. Código real y decisiones.
Qué problema estaba resolviendo
En esta sesión el objetivo es no hardcodear cosas en el test.
Para eso hago uso de un archivo de configuraciones y de un driver manager.
Ya que estos datos:
- driver
- browser elegido
- URL bajo prueba
- timeouts y opciones desperdigadas
se repetirían en cada test y esto no escala bien, ya que si quiero cambiar de por ejemplo browser elegido debería de hacer el cambio en cada test .java, algo que puede significar mantenimiento de una cantidad elevada de archivos .java
Así que en este “Sesión 4” armé la base para un framework serio:
✅ config.properties
✅ ConfigReader
✅ DriverManager
✅ y un PrimerTest que usa todo esto
Esto ERA lo hardcodeado (y por qué)
Mi PrimerTest funcionaba, pero estaba acoplado a:

Creación del driver
WebDriver driver = new ChromeDriver();🔴 Hardcodeado porque:
- Forzás Chrome
- Forzás driver local
- Forzás cómo se crea el driver
- configuraciones como headless / maximize / timeouts (que después se vuelven caos)
👉 Esto debería decidirse fuera del test, no en cada test.
URL directa
driver.get("https://demo.serenity.is/Account/Login/");🔴 Hardcodeado porque:
- La URL está fija
- No depende de entorno (dev / staging / prod)
- Para cambiarla hay que tocar código
👉 Esto va a config.properties.
Cierre del driver en el test
driver.quit();🔴 Hardcodeado a nivel flujo, no de valor:
- Cada test decide cuándo y cómo cerrar
- Si mañana querés screenshots en fallo, esto rompe el flujo
👉 El ciclo de vida del driver no es responsabilidad del test.
Y eso es exactamente lo que NO quiero.
Reencuadre mental (esto es importante)
Hardcodeado no es solo un string.
También es:
- una decisión fija
- una responsabilidad mal puesta
- algo que no puede cambiar sin tocar el test
Paso 1 — Crear config.properties
Ubicación (importante):
src/test/resources/config.properties

Contenido inicial (mínimo viable, pero ya escalable):
# Entorno
base.url=https://demo.serenity.is
# Navegador
browser=chrome
headless=false
window.maximize=true
# Timeouts (segundos)
timeout.implicit=0
timeout.explicit=10
timeout.pageLoad=30
# Ejecución remota (futuro)
run.remote=false
remote.url=http://localhost:4444/wd/hub
# Evidencias (futuro)
screenshots.on.failure=true
screenshots.path=target/screenshots
Paso 2 — Implementar ConfigReader
Objetivo: leer el .properties y exponer algo tipo:
ConfigReader.getProperty("base.url")
Ubicación:
src/main/java/com/cesar/qa/config/ConfigReader.java

Código:
// Leer datos desde un archivo .properties
// Si necesitas manejar configuraciones externas sin tocar el código, usa archivos .properties.
/* e.g:
Ejemplo de un archivo config.properties:
base.url=https://demo.serenity.is/
login.username=admin
login.password=serenity
Cómo usarlo en un test:
String baseUrl = ConfigReader.getProperty("base.url");
System.out.println("URL Base: " + baseUrl);
Ventaja: Puedes cambiar credenciales o URLs sin modificar el código.
*/
package com.cesar.qa.config;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
public class ConfigReader {
private static Properties properties = new Properties();
static {
try {
FileInputStream file = new FileInputStream("src/test/resources/config.properties");
properties.load(file);
} catch (IOException e) {
throw new RuntimeException("No se pudo cargar config.properties", e);
}
}
public static String getProperty(String key) {
return properties.getProperty(key);
}
}
Paso 3 — DriverManager (centralizar creación del driver)
El siguiente dolor era esto:
WebDriverManager.chromedriver().setup();
WebDriver driver = new ChromeDriver();
Eso no debería estar en cada test.
Así que creé un DriverManager que:
- lee
browseryheadlessdesdeconfig.properties - crea el driver correspondiente
- aplica timeouts y maximize
- expone
getDriver()yquitDriver()
Ubicación:
src/main/java/com/cesar/qa/config/DriverManager.java

Código (versión actual):
package com.cesar.qa.config;
import io.github.bonigarcia.wdm.WebDriverManager;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import java.time.Duration;
public class DriverManager {
private static WebDriver driver;
public static void initDriver() {
if (driver != null) return;
String browser = ConfigReader.getProperty("browser");
boolean headless = Boolean.parseBoolean(ConfigReader.getProperty("headless"));
if (browser == null) browser = "chrome";
switch (browser.toLowerCase()) {
case "chrome":
WebDriverManager.chromedriver().setup();
ChromeOptions options = new ChromeOptions();
if (headless) {
// "new" headless en Chrome moderno
options.addArguments("--headless=new");
}
options.addArguments("--disable-gpu");
options.addArguments("--no-sandbox");
driver = new ChromeDriver(options);
break;
default:
throw new RuntimeException("Browser no soportado: " + browser);
}
applyConfig(driver);
}
private static void applyConfig(WebDriver driver) {
int implicit = Integer.parseInt(ConfigReader.getProperty("timeout.implicit"));
int pageLoad = Integer.parseInt(ConfigReader.getProperty("timeout.pageLoad"));
boolean maximize = Boolean.parseBoolean(ConfigReader.getProperty("window.maximize"));
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(implicit));
driver.manage().timeouts().pageLoadTimeout(Duration.ofSeconds(pageLoad));
if (maximize) {
driver.manage().window().maximize();
}
}
public static WebDriver getDriver() {
if (driver == null) initDriver();
return driver;
}
public static void quitDriver() {
if (driver != null) {
driver.quit();
driver = null;
}
}
}
Paso 4 — PrimerTest usando DriverManager + ConfigReader
La idea era que el test quede así:
- init driver
- navegar usando config
- obtener título
- cerrar driver

Código (versión actual):
package com.cesar.qa.tests;
import com.cesar.qa.config.ConfigReader; // - importar ConfigReader
import com.cesar.qa.config.DriverManager; // - importar DriverManager
import org.openqa.selenium.WebDriver;
import org.testng.annotations.Test;
public class PrimerTest {
@Test
public void abrirSerenityis() {
// 1) Inicializa el WebDriver según lo que diga config.properties
// - browser=chrome
// - headless=true/false
// - window.maximize=true/false
// - timeouts
// Nota: Esto evita tener "new ChromeDriver()" en cada test.
DriverManager.initDriver();
// 2) Obtiene la instancia del driver creada por DriverManager
// (Si todavía no existe, la crea automáticamente).
WebDriver driver = DriverManager.getDriver();
// 3) Lee la URL base desde config.properties
// Ej: base.url=https://demo.serenity.is
String baseUrl = ConfigReader.getProperty("base.url");
// 4) Navega a la URL configurada
// (Esto reemplaza el hardcode: driver.get("https://demo.serenity.is/..."))
driver.get(baseUrl);
// 5) Validación / evidencia simple: imprimir el título de la página
// En esta etapa, el objetivo es confirmar que todo el wiring funciona.
String titulo = driver.getTitle();
System.out.println("Título de la página: " + titulo);
// 6) Cierra el navegador y limpia el driver para la próxima ejecución
// (Más adelante esto se moverá a un BaseTest con @AfterMethod)
DriverManager.quitDriver();
System.out.println("Test ejecutado correctamente");
}
}
Ejecución

Todo ok 👍
Resultado
Con esto logré:
✅ Los tests ya no tienen URL hardcodeada
✅ Cambiar headless o base.url es cambiar un archivo, no código
✅ Creación del driver centralizada
✅ Timeouts y maximize centralizados
✅ Base sólida para el próximo paso
Esto todavía no es un framework “final”.
Es una base que funciona y que puedo mejorar sin romper todo.
Próximo paso
Ahora que el driver y config están centralizados, lo siguiente es:
BaseTestcon@BeforeMethod / @AfterMethodpara no repetirinit/quiten cada test- y recién después empezar con
BasePage(wrapper y waits)
🔗 Todo el código de esta serie está en: github.com/cesarbeassuarez/qa-automation-lab
📂 selenium-java
—
Temas conectados:
Sesión 2 de este lab y Sesión 3 de este lab de Selenium con java.