2 Patrones de diseño importantes y mejores prácticas de Selenium

En este tutorial aprenderemos sobre los patrones de diseño de Selenium y las mejores prácticas mientras trabajamos con el desarrollo del marco de automatización de Selenium (marco híbrido en selenium), hay dos variaciones de Diseño de marco o modelo de marco que tenemos que considerar, que son: 

Necesitamos saber y comprender por qué se requiere un patrón de diseño de lenguaje cuando estamos desarrollando nuestro marco en uno de los modelos de marco de Selenium. Sugerimos pasar por los segmentos anteriores de la Serie de tutoriales de desarrollo de Selenium Framework para obtener toda la comprensión.

Patrones de diseño de selenio y mejores prácticas: marco híbrido en selenio
Patrones de diseño de selenio y mejores prácticas: marco híbrido en selenio

Entendamos eso en detalle: 

patrones de diseño de selenio y mejores prácticas ,marco híbrido en selenio

Al diseñar cualquier marco, debemos considerar alguna arquitectura de diseño, es decir, patrones de diseño de selenio y mejores prácticas, y según la necesidad del tipo de modelo del marco, debemos seleccionar un idioma. Patrón de diseño para resolver el estado del problema del diseño del marco en su conjunto.

Por lo tanto, solo para concluir, podemos elegir un modelo de marco de Selenium (híbrido, modelo de objeto de página, basado en datos, etc.), pero para implementar el modelo, debemos seguir e implementar algún patrón de diseño de lenguaje (por ejemplo, patrones de diseño java / C # ) 

Por qué necesitamos el patrón de diseño de selenio y las mejores prácticas al crear Selenium Framework: 

  • Establecer el diseño de stand del framework para desarrollar diferentes herramientas y utilidades.
  • Cualquier lenguaje (por ejemplo, Java / C #, etc.) tiene múltiples patrones de diseño, y cada patrón de diseño tiene sus propios pros y contras y está destinado a resolver diferentes enunciados de problemas.
  • Diseño estándar y robusto entre los miembros del equipo. 
  • Reutilización de código, de forma estructurada y estandarizada.
  • El mantenimiento y la depuración del código se vuelven más fáciles.

Qué patrones de diseño se utilizarán en Selenium Framework: 

Hay algunos patrones de diseño que puede usar para implementar diferentes áreas del marco, como un ejemplo: 

  • Patrón de diseño Singleton para implementar los datos configurables (para el marco de automatización, como el nombre del navegador, el entorno a ejecutar, la URL, etc.). 
  • Patrón de diseño de fábrica y abstracto de fábrica (puede implementar los diversos controladores múltiples y la implementación del navegador utilizando este patrón de diseño y también si desea desarrollar la función de trabajar con varias fuentes de datos como excel, propiedades, YAML, base de datos, pdf, imagen, etc., entonces también puede usar el patrón de diseño de fábrica / abstracto).

Haremos la plantilla de codificación en vivo de todo el Framework en las próximas publicaciones aquí.

Patrón de diseño Singleton para marco híbrido en Selenium: 

Singleton Design Pattern es un patrón en el que puede crear solo un objeto de una clase y usar el mismo objeto para acceder a los métodos de la clase; Podríamos usar el patrón de diseño en el configurador donde solo necesitamos leer los datos de configuración y podemos cargar en algún almacén de datos (cualquier tipo de estructura de datos que pueda usar cuando sea necesario mientras se ejecuta desde cualquier clase y método) 

Entonces podríamos lograr lo mismo de la siguiente manera mientras diseñamos lo mismo con el patrón de diseño Singleton. 

NOTA: Diseñaremos y desarrollaremos el marco desde cero en la próxima sección de la serie de tutoriales, pero este tutorial específico le proporcionará información sobre la necesidad del patrón de diseño.

package com.cyborg.core.generic.dataUtils;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedHashMap;
import java.util.Properties;
import java.util.Set;

import org.apache.log4j.PropertyConfigurator;


// This is the SingleTon Class 
public class PropertiesDataUtils {

   private Properties properties = null;
   public static LinkedHashMap<String, String> configDataStore = new LinkedHashMap<String, String>();
   InputStream is = null;

// This is the static and private reference of the class which you could use anywhere in you framework 
   private static PropertiesDataUtils propertiesDataUtils = null;
   boolean centralizeLog  = false;


// This is the Private constructor to create the object but you can not access this from outside the class to maintain the design of the SingleTon pattern ie only one object creation .

   private PropertiesDataUtils(String filePath) {
       generateDataStore(filePath);
       centralizeLog =  Boolean.parseBoolean(PropertiesDataUtils.configDataStore.get("centralizedLog"));
       if(centralizeLog)
           PropertyConfigurator.configure(System.getProperty("user.dir")+"//src//test//resources//config//log4j_central.properties");
         else
            PropertyConfigurator.configure(System.getProperty("user.dir")+"//src//test//resources//config//log4j_local.properties");
   }

   private PropertiesDataUtils() {

   }
  
 
// This method basically create the instance of the SingleTon class 

   public static PropertiesDataUtils getInstance(String filePath) {
       if (propertiesDataUtils == null)
           propertiesDataUtils = new PropertiesDataUtils(filePath);
       return propertiesDataUtils;
   }


// this method basically creates the datastore where you want to store all the config data as discussed previously 

   private void generateDataStore(String filePath) {
       try {
           this.properties = new Properties();
           is=new FileInputStream(filePath);
           properties.load(is);
           overrideFromEnvironment();
           Set<Object> keys = loadAllKeys();
           for (Object k : keys) {
               String key = (String) k;
               configDataStore.put(key, getPropertyValue(key));
           }

       } catch (FileNotFoundException fileNotFoundException) {
           String exceptionData = String.valueOf(fileNotFoundException.getCause().getMessage());

       } catch (IOException ioException) {
           String exceptionData = String.valueOf(ioException.getCause().getMessage());
       } finally {
           if (null != is) {
               try {
                   is.close();
               } catch (Exception e) {
                   String exceptionData = String.valueOf(e.getCause().getMessage());

               }
           }

       }
   }


// This method is used to load all the keys from the properties file.

   private Set<Object> loadAllKeys() {
       Set<Object> keys = this.properties.keySet();
       return keys;
   }

   private String getPropertyValue(String key) {
       return this.properties.getProperty(key);
   }
   private void setPropertyValue(String key,String value) {
        this.properties.setProperty(key,value);
   }
  
  private void overrideFromEnvironment() {

     if (this.properties.getProperty("run_on_jenkins").equals("true")) {
        System.out.println("SET run_on_jenkins FLAG TO FALSE IN YOUR PROPERTIES FILE TO RUN LOCALLY....");
        String build_number = System.getenv("BUILD_NUMBER");
        this.properties.setProperty("build_number", build_number);
     }
    
  }
}

Con este enfoque, podríamos usar el patrón de diseño Singleton y usarlo en nuestro marco.

Patrón de diseño de fábrica en el marco de selenio: 

En el patrón de diseño de fábrica, creamos una clase (la llamamos clase de fábrica) y, por otro lado, tenemos una interfaz y eventualmente implementado por “n” número de clases.

La clase de fábrica básicamente devuelve el objeto de las clases anteriores (según la necesidad), por lo que no tiene que lidiar con lo anterior “N” número de objetos de clases; más bien, puede crear un objeto de la clase Factory y llamar al método de la clase Factory que devuelve el Objeto de línea de base necesario para las clases requeridas entre las clases “n” de adobe.

Ahora, este diseño puede considerarlo mientras crea la implementación diferente de Webdriver / navegador. 

Tenemos varios navegadores y la implementación con un tipo diferente de controlador Selenium (por ejemplo, LocalDriver, RemoteDriver, ThreadDriver, etc.) y cuando necesite un tipo específico de controlador y un tipo específico de navegador, puede mencionarlo en el archivo de configuración. y en función de la necesidad, la clase de fábrica le proporcionará la instancia del controlador y el navegador para que su script de automatización pueda seguir utilizándolo. 

Aquí está la base del código para implementar este patrón de diseño mientras se crean interacciones entre el controlador y el navegador: 

Diseño de interfaz : 

package com.cyborg.core.web.utils.driverUtils;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.RemoteWebDriver;



public interface IDriver {
   public WebDriver init(String browserName);

}


Número "N" de implementación de clases de navegación (que están implementando la interfaz):

package com.cyborg.core.web.utils.driverUtils;


import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.edge.EdgeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;


import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.safari.SafariDriver;

public class LocalDriver implements IDriver {
   public WebDriver init(String browserName) {


       String pathToDriver = getDriverPath(browserName);

       if (null != browserName) {

           switch (browserName) {
               case "chrome":
                   System.setProperty("webdriver.chrome.driver",
                           pathToDriver);
                   return new ChromeDriver();
               case "firefox":
                   System.setProperty("webdriver.gecko.driver", pathToDriver);
                   return new FirefoxDriver();

               default:
                   System.setProperty("webdriver.chrome.driver", pathToDriver);
                   return new ChromeDriver();
           }
       } else {
           System.setProperty("webdriver.chrome.driver",
                   pathToDriver);
           return new ChromeDriver();
       }
   }



   private String getDriverPath(String browserName) {

       String osData = System.getProperty("os.name").toLowerCase().split("\\s")[0];
       if (null != osData) {
           if (osData.equalsIgnoreCase("mac")) {
               return "./DriversExe/" + osData + "_" + browserName;

           } else if (osData.contains("nux") || (osData.contains("nix"))) {
               return "./DriversExe/linux_" + browserName;
           } else if (osData.contains("win")) {
               return "./DriversExe/" + osData + "_" + browserName + ".exe";
           }
       }
       return null;
   }
}

Aquí está la implementación de la clase Remote Driver: 

package com.cyborg.core.web.utils.driverUtils;


import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;

import com.cyborg.core.generic.dataUtils.PropertiesDataUtils;


import java.net.MalformedURLException;
import java.net.URL;

public class RemoteDriver implements IDriver {

   DesiredCapabilities caps;
   String remoteHuburl=PropertiesDataUtils.configDataStore.get("WEB_GRID_IP");

   @Override
   public WebDriver init(String browserName) {

       if (browserName != null) {

           switch (browserName) {
               case "firefox":
                   try {
                       return new RemoteWebDriver(new URL(remoteHuburl), caps.firefox());
                   } catch (MalformedURLException malformedUrlEx) {

                       malformedUrlEx.getCause().getMessage();
                       malformedUrlEx.printStackTrace();
                   }
               case "chrome":
                   try {
                       return new RemoteWebDriver(new URL(remoteHuburl), caps.chrome());
                   } catch (MalformedURLException malformedUrlEx) {

                       malformedUrlEx.getCause().getMessage();
                       malformedUrlEx.printStackTrace();
                   }
               case "ie":
                   try {
                       return new RemoteWebDriver(new URL(remoteHuburl), caps.internetExplorer());
                   } catch (MalformedURLException malformedUrlEx) {

                       malformedUrlEx.getCause().getMessage();
                       malformedUrlEx.printStackTrace();

                   }
               default:
                   try {
                       return new RemoteWebDriver(new URL(remoteHuburl), caps.chrome());
                   } catch (MalformedURLException malformedUrlEx) {

                       malformedUrlEx.getCause().getMessage();
                       malformedUrlEx.printStackTrace();
                   }
           }
           return null;
       } else {
           return null;
       }
   }

Aquí está la implementación de la clase Factory, que proporciona el navegador y el objeto de clase de controlador respectivos: 

package com.cyborg.core.web.utils.driverUtils;



public class DriverProvider {

   public IDriver getDriver(String typeOfDriver) {


       if (typeOfDriver != null) {
           switch (typeOfDriver) {
               case "local":
                   return new LocalDriver();
               case "remote":
                   return new RemoteDriver();
              
               default:
                   return new LocalDriver();
           }
       } else {
           return null;
       }
   }

}

Asimismo, puede implementar la Appium driver junto con el mismo diseño, solo proporcione la implementación y declare un método en las interfaces IDriver. 

Conclusión: Con esto, estamos concluyendo aquí cómo puede usar patrones de diseño de lenguaje como parte de los patrones de diseño de Selenium y las mejores prácticas mientras desarrolla el marco híbrido en Selenium; En los próximos segmentos del tutorial, crearemos el marco del modelo de objeto de página para Selenium Automation.

Para obtener el Tutorial general sobre selenio, puede visitar aquí

Sobre Debarghya

Yo mismo, Debarghya Roy, soy un ARQUITECTO de ingeniería que trabaja con una compañía de Fortune 5 y un colaborador de código abierto, con alrededor de 12 años de experiencia / conocimientos en varias tecnologías.
He trabajado con diversas tecnologías como Java, C #, Python, Groovy, UI Automation (Selenium), Mobile Automation (Appium), API / Backend Automation, Performance Engineering (JMeter, Locust), Security Automation (MobSF, OwAsp, Kali Linux , Astra, ZAP, etc.), RPA, automatización de ingeniería de procesos, automatización de mainframe, desarrollo de back-end con SpringBoot, Kafka, Redis, RabitMQ, ELK stack, GrayLog, Jenkins y también con experiencia en tecnologías de nube, DevOps, etc.
Vivo en Bangalore, India con mi esposa y tengo pasión por los blogs, la música, tocar la guitarra y mi Filosofía de vida es Educación para Todos, que dio origen a LambdaGeeks. Vamos a conectarnos a través de enlaces: https://www.linkedin.com/in/debarghya-roy/

Deja un comentario

Tu dirección de correo electrónico no será publicada.Los campos obligatorios están marcados *

Frikis Lambda