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.

Código Java de PrimerTest con flechas verdes señalando líneas hardcodeadas: ChromeDriver, URL y driver.quit

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:

PrimerTest.java en IntelliJ mostrando código acoplado: new ChromeDriver(), URL directa y cierre manual del driver
El test funcionaba, pero tenía decisiones fijas que no escalan.

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

Estructura del proyecto en IntelliJ mostrando config.properties en src/test/resources con configuraciones de entorno, navegador, timeouts y ejecución remota
Ubicación: 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

Clase ConfigReader.java en IntelliJ que lee propiedades desde config.properties usando FileInputStream y Properties
ConfigReader expone getProperty() para acceder a cualquier configuración.

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 browser y headless desde config.properties
  • crea el driver correspondiente
  • aplica timeouts y maximize
  • expone getDriver() y quitDriver()

Ubicación:

src/main/java/com/cesar/qa/config/DriverManager.java

Clase DriverManager.java en IntelliJ con métodos initDriver, getDriver y quitDriver que centralizan la creación del WebDriver
DriverManager lee browser y headless desde config.properties.

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
PrimerTest.java refactorizado usando DriverManager.initDriver(), DriverManager.getDriver() y ConfigReader.getProperty() en lugar de código hardcodeado
El test ahora no tiene URLs ni drivers hardcodeados.

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

Consola de IntelliJ mostrando ejecución exitosa del test: Tests passed 1, Failures 0, exit code 0

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:

  • BaseTest con @BeforeMethod / @AfterMethod para no repetir init/quit en 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.