page object model with page factory selenium tutorial
Este tutorial en profundidad explica todo sobre el modelo de objetos de página (POM) con ejemplos de uso de Pagefactory. También puede aprender la implementación de POM en Selenium:
En este tutorial, entenderemos cómo crear un modelo de objetos de página utilizando el enfoque de Page Factory. Nos centraremos en:
- Clase de fábrica
- Cómo crear un POM básico usando Page Factory Pattern
- Diferentes anotaciones utilizadas en el enfoque de fábrica de páginas
Antes de ver qué es Pagefactory y cómo se puede usar junto con el modelo de objetos de página, comprendamos qué es el modelo de objetos de página, que comúnmente se conoce como POM.
=> Visite aquí para ver la serie de capacitación sobre selenio para todos.
Lo que vas a aprender:
- ¿Qué es el modelo de objetos de página (POM)?
- ¿Qué es Pagefactory?
- POM usando Page Factory
- Preguntas frecuentes
- Conclusión
¿Qué es el modelo de objetos de página (POM)?
Las terminologías teóricas describen la Modelo de objeto de página como un patrón de diseño utilizado para construir un repositorio de objetos para los elementos web disponibles en la aplicación bajo prueba. Pocos otros se refieren a él como un marco para la automatización de Selenium para la aplicación dada bajo prueba.
Sin embargo, lo que he entendido sobre el término Modelo de objeto de página es:
#1) Es un patrón de diseño en el que tiene un archivo de clase Java separado correspondiente a cada pantalla o página de la aplicación. El archivo de clase podría incluir el repositorio de objetos de los elementos de la interfaz de usuario, así como los métodos.
#2) En caso de que haya elementos web enormes en una página, la clase de repositorio de objetos para una página se puede separar de la clase que incluye métodos para la página correspondiente.
Ejemplo: Si la página Registrar cuenta tiene muchos campos de entrada, entonces podría haber una clase RegisterAccountObjects.java que forma el repositorio de objetos para los elementos de la interfaz de usuario en la página de registro de cuentas.
Se podría crear un archivo de clase independiente RegisterAccount.java que extienda o herede RegisterAccountObjects que incluya todos los métodos que realizan diferentes acciones en la página.
#3) Además, podría haber un paquete genérico con un archivo {roperties, datos de prueba de Excel y métodos comunes en un paquete.
Ejemplo: DriverFactory que se puede utilizar muy fácilmente en todas las páginas de la aplicación
Entendiendo POM con el ejemplo
Controlar Aquí para obtener más información sobre POM.
A continuación se muestra una instantánea de la página web:
Al hacer clic en cada uno de estos enlaces, el usuario se redirigirá a una nueva página.
Aquí está la instantánea de cómo se construye la estructura del proyecto con Selenium utilizando el modelo de objetos Page correspondiente a cada página del sitio web. Cada clase de Java incluye un repositorio de objetos y métodos para realizar diferentes acciones dentro de la página.
Además, habrá otro JUNIT o TestNG o un archivo de clase Java que invoca llamadas a archivos de clase de estas páginas.
¿Por qué utilizamos el modelo de objetos de página?
Hay un rumor sobre el uso de este poderoso marco de Selenium llamado POM o modelo de objetos de página. Ahora, la pregunta surge como '¿Por qué utilizar POM?'.
La respuesta simple a esto es que POM es una combinación de marcos modulares e híbridos impulsados por datos. Es un enfoque para organizar sistemáticamente los scripts de tal manera que facilita que el control de calidad mantenga el código libre de problemas y también ayuda a prevenir el código redundante o duplicado.
Por ejemplo, si hay un cambio en el valor del localizador en una página específica, entonces es muy fácil identificar y realizar ese cambio rápido solo en el script de la página respectiva sin afectar el código en otra parte.
Usamos el concepto de Modelo de objeto de página en Selenium Webdriver por las siguientes razones:
- Se crea un repositorio de objetos en este modelo POM. Es independiente de los casos de prueba y se puede reutilizar para un proyecto diferente.
- La convención de nomenclatura de los métodos es muy fácil, comprensible y más realista.
- En el modelo de objetos de página, creamos clases de página que se pueden reutilizar en otro proyecto.
- El modelo de objetos Page es fácil para el marco desarrollado debido a sus diversas ventajas.
- En este modelo, se crean clases separadas para diferentes páginas de una aplicación web como la página de inicio de sesión, la página de inicio, la página de detalles del empleado, la página de cambio de contraseña, etc.
- Si hay algún cambio en cualquier elemento de un sitio web, solo necesitamos realizar cambios en una clase y no en todas las clases.
- El script diseñado es más reutilizable, legible y fácil de mantener en el enfoque del modelo de objetos de página.
- Su estructura de proyecto es bastante sencilla y comprensible.
- Puede usar PageFactory en el modelo de objetos de página para inicializar el elemento web y almacenar elementos en la caché.
- TestNG también se puede integrar en el enfoque del Modelo de objetos de página.
Implementación de POM simple en selenio
# 1) Escenario para automatizar
Ahora automatizamos el escenario dado usando el Modelo de objetos de página.
El escenario se explica a continuación:
Paso 1: Inicie el sitio 'https: //demo.vtiger.com'.
Paso 2: Ingrese la credencial válida.
Paso 3: Inicie sesión en el sitio.
Paso 4: Verifique la página de inicio.
Paso 5: Cierre la sesión del sitio.
Paso 6: Cierre el navegador.
# 2) Scripts de selenio para el escenario anterior en POM
Ahora creamos la estructura POM en Eclipse, como se explica a continuación:
Paso 1: Cree un proyecto en Eclipse - Estructura basada en POM:
a) Crear proyecto “Modelo de objetos de página”.
b) Cree 3 paquetes bajo el proyecto.
- Biblioteca
- paginas
- Casos de prueba
Biblioteca: Debajo de esto, colocamos los códigos que necesitan ser llamados una y otra vez en nuestros casos de prueba, como el inicio del navegador, capturas de pantalla, etc. El usuario puede agregar más clases en función de la necesidad del proyecto.
Paginas: Bajo esto, las clases se crean para cada página en la aplicación web y pueden agregar más clases de página según el número de páginas en la aplicación.
Casos de prueba: Debajo de esto, escribimos el caso de prueba de inicio de sesión y podemos agregar más casos de prueba según sea necesario para probar toda la aplicación.
c) Las clases de los Paquetes se muestran en la siguiente imagen.
Paso 2: Cree las siguientes clases en el paquete de la biblioteca.
Browser.java: En esta clase, se definen 3 navegadores (Firefox, Chrome e Internet Explorer) y se llama en el caso de prueba de inicio de sesión. Según el requisito, el usuario también puede probar la aplicación en diferentes navegadores.
|_+_|ScreenShot.java: En esta clase, se escribe un programa de captura de pantalla y se llama en el caso de prueba cuando el usuario desea tomar una captura de pantalla de si la prueba falla o pasa.
|_+_|Paso 3 : Cree clases de página en el paquete de páginas.
HomePage.java: Esta es la clase de página de inicio, en la que se definen todos los elementos y métodos de la página de inicio.
|_+_|LoginPage.java: Esta es la clase de página de inicio de sesión, en la que se definen todos los elementos de la página de inicio de sesión y los métodos.
|_+_|Paso 4: Cree casos de prueba para el escenario de inicio de sesión.
LoginTestCase.java: Esta es la clase LoginTestCase, donde se ejecuta el caso de prueba. El usuario también puede crear más casos de prueba según la necesidad del proyecto.
|_+_|Paso 5: Ejecute 'LoginTestCase.java'.
Paso 6: Salida del modelo de objetos de página:
- Inicie el navegador Chrome.
- El sitio web de demostración se abre en el navegador.
- Inicie sesión en el sitio de demostración.
- Verifique la página de inicio.
- Cierre la sesión del sitio.
- Cierre el navegador.
Ahora, exploremos el concepto principal de este tutorial que llama la atención, es decir, “Pagefactory”.
¿Qué es Pagefactory?
PageFactory es una forma de implementar el 'Modelo de objetos de página'. Aquí, seguimos el principio de separación del repositorio de objetos de página y los métodos de prueba. Es un concepto incorporado de Page Object Model que está muy optimizado.
Tengamos ahora más claridad sobre el término Pagefactory.
#1) En primer lugar, el concepto llamado Pagefactory, proporciona una forma alternativa en términos de sintaxis y semántica para crear un repositorio de objetos para los elementos web en una página.
#2) En segundo lugar, utiliza una estrategia ligeramente diferente para la inicialización de los elementos web.
#3) El repositorio de objetos para los elementos web de la interfaz de usuario se puede construir usando:
- 'POM sin Pagefactory' habitual y,
- Alternativamente, puede utilizar 'POM con Pagefactory'.
A continuación se muestra una representación pictórica del mismo:
Ahora veremos todos los aspectos que diferencian el POM habitual de POM con Pagefactory.
a) La diferencia en la sintaxis de localizar un elemento usando POM habitual vs POM con Pagefactory.
Por ejemplo , Haga clic en Aquí para localizar el campo de búsqueda que aparece en la página.
POM sin Pagefactory:
# 1) A continuación se muestra cómo ubica el campo de búsqueda utilizando el POM habitual:
|_+_|# 2) El siguiente paso pasa el valor 'inversión' al campo de búsqueda NSE.
|_+_|POM usando Pagefactory:
#1) Puede localizar el campo de búsqueda utilizando Pagefactory como se muestra a continuación.
La anotación @FindBy se utiliza en Pagefactory para identificar un elemento, mientras que POM sin Pagefactory utiliza el driver.findElement () método para localizar un elemento.
La segunda declaración de Pagefactory después @FindBy está asignando un tipo de WebElement clase que funciona exactamente de manera similar a la asignación de un nombre de elemento de tipo WebElement class como tipo de retorno del método driver.findElement () que se utiliza en el POM habitual (searchNSETxt en este ejemplo).
Miraremos el @FindBy anotaciones en detalle en la próxima parte de este tutorial.
|_+_|#2) El siguiente paso pasa el valor 'inversión' al campo de búsqueda NSE y la sintaxis sigue siendo la misma que la del POM habitual (POM sin Pagefactory).
|_+_|b) La diferencia en la estrategia de Inicialización de Elementos Web usando POM habitual vs POM con Pagefactory.
Usando POM sin Pagefactory:
A continuación se muestra un fragmento de código para establecer la ruta del controlador de Chrome. Se crea una instancia de WebDriver con el nombre del controlador y ChromeDriver se asigna al 'controlador'. El mismo objeto controlador se utiliza para iniciar el sitio web de la Bolsa de Valores Nacional, ubicar el cuadro de búsqueda e ingresar el valor de la cadena en el campo.
El punto que deseo resaltar aquí es que cuando es POM sin fábrica de páginas, la instancia del controlador se crea inicialmente y cada elemento web se inicializa nuevamente cada vez que hay una llamada a ese elemento web usando driver.findElement () o driver .findElements ().
Esta es la razón por la que, con un nuevo paso de driver.findElement () para un elemento, la estructura DOM se examina nuevamente y se actualiza la identificación del elemento en esa página.
|_+_|Usando POM con Pagefactory:
Además de usar la anotación @FindBy en lugar del método driver.findElement (), el siguiente fragmento de código se usa adicionalmente para Pagefactory. El método estático initElements () de la clase PageFactory se usa para inicializar todos los elementos de la interfaz de usuario en la página tan pronto como se carga la página.
|_+_|La estrategia anterior hace que el enfoque de PageFactory sea ligeramente diferente del POM habitual. En el POM habitual, el elemento web debe inicializarse explícitamente, mientras que en el enfoque de Pagefactory todos los elementos se inicializan con initElements () sin inicializar explícitamente cada elemento web.
Por ejemplo: Si el WebElement se declaró pero no se inicializó en el POM habitual, se produce el error 'initialize variable' o NullPointerException. Por lo tanto, en el POM habitual, cada WebElement debe inicializarse explícitamente. PageFactory viene con una ventaja sobre el POM habitual en este caso.
No inicialicemos el elemento web BDate (POM sin Pagefactory), puede ver que se muestra el error 'Inicializar variable' y solicita al usuario que la inicialice en nulo, por lo tanto, no puede asumir que los elementos se inicializan implícitamente al ubicarlos.
Elemento BDate inicializado explícitamente (POM sin Pagefactory):
Ahora, veamos un par de casos de un programa completo que usa PageFactory para descartar cualquier ambigüedad en la comprensión del aspecto de implementación.
Ejemplo 1:
- Vaya a 'http://www.nseindia.com/'
- En el menú desplegable junto al campo de búsqueda, seleccione 'Derivados de divisas'.
- Busque 'USDINR'. Verifique el texto 'Dólar estadounidense-Rupia india - USDINR' en la página resultante.
Estructura del programa:
- PagefactoryClass.java que incluye un repositorio de objetos que utiliza el concepto de fábrica de páginas para nseindia.com que es un constructor para inicializar todos los elementos web, se crea el método selectCurrentDerivative () para seleccionar el valor del campo desplegable del cuadro de búsqueda, selectSymbol () para seleccionar un símbolo en el página que aparece a continuación y verifytext () para verificar si el encabezado de la página es el esperado o no.
- NSE_MainClass.java es el archivo de clase principal que llama a todos los métodos anteriores y realiza las acciones respectivas en el sitio NSE.
PagefactoryClass.java
|_+_|NSE_MainClass.java
|_+_|Ejemplo 2:
- Vaya a 'https://www.shoppersstop.com/brands'
- Vaya al enlace Haute curry.
- Verifique si la página de Haute Curry contiene el texto 'Comenzar algo nuevo'.
Estructura del programa
- shopperstopPagefactory.java que incluye un repositorio de objetos usando el concepto pagefactory para shoppersstop.com que es un constructor para inicializar todos los elementos web se crea, los métodos closeExtraPopup () para manejar un cuadro emergente de alerta que se abre, haga clic en OnHauteCurryLink () para hacer clic en Haute Curry Vincula y verificaStartNewSomething () para verificar si la página de Haute Curry contiene el texto 'Comenzar algo nuevo'.
- Shopperstop_CallPagefactory.java es el archivo de clase principal que llama a todos los métodos anteriores y realiza las acciones respectivas en el sitio NSE.
shopperstopPagefactory.java
|_+_|Shopperstop_CallPagefactory.java
|_+_|POM usando Page Factory
Tutoriales en video - POM con Page Factory
Parte I
Parte II
Una clase Factory se utiliza para simplificar y facilitar el uso de Page Objects.
- Primero, necesitamos encontrar los elementos web por anotación. @FindBy en clases de página .
- Luego, inicialice los elementos usando initElements () al crear una instancia de la clase de página.
#1) @FindBy:
La anotación @FindBy se usa en PageFactory para ubicar y declarar los elementos web usando diferentes localizadores.Aquí, pasamos el atributo así como su valor usado para ubicar el elemento web a la anotación @FindBy y luego se declara el WebElement.
Hay dos formas en las que se puede utilizar la anotación.
Por ejemplo:
|_+_|Sin embargo, la primera es la forma estándar de declarar WebElements.
'Cómo' es una clase y tiene variables estáticas como ID, XPATH, CLASSNAME, LINKTEXT, etc.
'usando' - Asignar un valor a una variable estática.
En lo de arriba ejemplo , hemos utilizado el atributo 'id' para localizar el elemento web 'Correo electrónico'. De manera similar, podemos usar los siguientes localizadores con las anotaciones @FindBy:
- nombre de la clase
- css
- nombre
- xpath
- tagName
- Texto del enlace
- parcialLinkText
# 2) initElements ():
InitElements es un método estático de la clase PageFactory que se utiliza para inicializar todos los elementos web ubicados por la anotación @FindBy. Por lo tanto, instanciar las clases de Page fácilmente.
|_+_|También debemos entender que POM sigue los principios de OOPS.
- Los elementos web se declaran como variables miembro privadas (ocultación de datos).
- Vinculación de WebElements con los métodos correspondientes (encapsulación).
Pasos para crear POM usando el patrón de fábrica de páginas
#1) Cree un archivo de clase Java independiente para cada página web.
#2) En cada clase, todos los WebElements deben declararse como variables (usando la anotación - @FindBy) e inicializarse usando el método initElement (). Los WebElements declarados deben inicializarse para ser utilizados en los métodos de acción.
#3) Defina los métodos correspondientes que actúen sobre esas variables.
Tomemos un ejemplo de un escenario simple:
- Abra la URL de una aplicación.
- Escriba la dirección de correo electrónico y la contraseña.
- Haga clic en el botón Iniciar sesión.
- Verifique el mensaje de inicio de sesión exitoso en la página de búsqueda.
Capa de página
Aquí tenemos 2 páginas,
- Página principal - La página que se abre cuando se ingresa la URL y donde ingresamos los datos para iniciar sesión.
- SearchPage - Una página que se muestra después de iniciar sesión correctamente.
En Page Layer, cada página de la aplicación web se declara como una clase Java separada y sus localizadores y acciones se mencionan allí.
Pasos para crear POM con ejemplo en tiempo real
# 1) Cree una clase Java para cada página:
En esto ejemplo , accederemos a 2 páginas web, las páginas “Inicio” y “Búsqueda”.
Por lo tanto, crearemos 2 clases Java en Page Layer (o en un paquete, por ejemplo, com.automation.pages).
|_+_|# 2) Defina WebElements como variables usando Annotation @FindBy:
Estaríamos interactuando con:
- Correo electrónico, contraseña, campo de botón de inicio de sesión en la página de inicio.
- Mensaje exitoso en la página de búsqueda.
Entonces definiremos WebElements usando @FindBy
Por ejemplo: Si vamos a identificar EmailAddress usando el atributo id, entonces su declaración de variable es
|_+_|# 3) Crea métodos para acciones realizadas en WebElements.
Las siguientes acciones se realizan en WebElements:
- Escriba acción en el campo Dirección de correo electrónico.
- Escriba acción en el campo Contraseña.
- Haga clic en acción en el botón Iniciar sesión.
Por ejemplo, Los métodos definidos por el usuario se crean para cada acción en el WebElement como,
|_+_|Aquí, el Id se pasa como un parámetro en el método, ya que el usuario enviará la entrada desde el caso de prueba principal.
Nota :Se debe crear un constructor en cada una de las clases en la capa de página, para obtener la instancia del controlador de la clase principal en la capa de prueba y también para inicializar WebElements (objetos de página) declarados en la clase de página usando PageFactory.InitElement () .
No iniciamos el controlador aquí, sino que su instancia se recibe de la clase principal cuando se crea el objeto de la clase de capa de página.
InitElement () - se usa para inicializar los WebElements declarados, usando la instancia del controlador de la clase principal. En otras palabras, los WebElements se crean utilizando la instancia del controlador. Solo después de inicializar los WebElements, se pueden usar en los métodos para realizar acciones.
Se crean dos clases de Java para cada página, como se muestra a continuación:
HomePage.java
|_+_|SearchPage.Java
|_+_|Capa de prueba
Los casos de prueba se implementan en esta clase. Creamos un paquete separado, por ejemplo, com.automation.test y luego creamos una clase Java aquí (MainClass.java)
Pasos para crear casos de prueba:
- Inicialice el controlador y abra la aplicación.
- Cree un objeto de la clase PageLayer (para cada página web) y pase la instancia del controlador como parámetro.
- Usando el objeto creado, haga una llamada a los métodos en la clase PageLayer (para cada página web) para realizar acciones / verificación.
- Repita el paso 3 hasta que se realicen todas las acciones y luego cierre el controlador.
Jerarquía de tipos de anotación utilizada para declarar elementos web
Las anotaciones se utilizan para ayudar a construir una estrategia de ubicación para los elementos de la interfaz de usuario.
# 1) @FindBy
Cuando se trata de Pagefactory, @FindBy actúa como una varita mágica. Agrega todo el poder al concepto. Ahora sabe que la anotación @FindBy en Pagefactory funciona igual que la del driver.findElement () en el modelo de objeto de página habitual. Se utiliza para localizar WebElement / WebElements con un criterio .
# 2) @FindBys
Se utiliza para localizar WebElement con más de un criterio y debe cumplir con todos los criterios dados. Estos criterios deben mencionarse en una relación padre-hijo. En otras palabras, esto usa la relación condicional AND para ubicar los WebElements usando los criterios especificados. Utiliza múltiples @FindBy para definir cada criterio.
Por ejemplo:
Código fuente HTML de un WebElement:
En POM:
|_+_|En el ejemplo anterior, el WebElement 'SearchButton' se encuentra solo si coincide con ambos los criterios cuyo valor de id es 'searchId_1' y el valor del nombre es 'search_field'. Tenga en cuenta que el primer criterio pertenece a una etiqueta principal y el segundo criterio para una etiqueta secundaria.
# 3) @FindAll
Se utiliza para localizar WebElement con más de un criterio y debe coincidir con al menos uno de los criterios dados. Esto usa relaciones condicionales OR para ubicar WebElements. Utiliza múltiples @FindBy para definir todos los criterios.
Por ejemplo:
Código fuente HTML:
En POM:
|_+_|En el ejemplo anterior, el nombre de usuario de WebElement se encuentra si coincide con al menos uno de los criterios mencionados.
# 4) @CacheLookUp
Cuando WebElement se usa con más frecuencia en casos de prueba, Selenium busca WebElement cada vez que se ejecuta el script de prueba. En esos casos, en los que determinados WebElements se utilizan globalmente para todos los TC ( Por ejemplo, El escenario de inicio de sesión ocurre para cada TC), esta anotación se puede usar para mantener esos WebElements en la memoria caché una vez que se lee por primera vez.
Esto, a su vez, ayuda a que el código se ejecute más rápido porque cada vez no tiene que buscar el WebElement en la página, sino que puede obtener su referencia de la memoria.
Puede ser un prefijo con cualquiera de @FindBy, @FindBys y @FindAll.
Por ejemplo:
|_+_|También tenga en cuenta que esta anotación debe usarse solo para WebElements cuyo valor de atributo (como xpath, nombre de identificación, nombre de clase, etc.) no cambia con mucha frecuencia. Una vez que el WebElement se encuentra por primera vez, mantiene su referencia en la memoria caché.
Entonces, cuando ocurre un cambio en el atributo de WebElement después de unos días, Selenium no podrá ubicar el elemento, porque ya tiene su referencia anterior en su memoria caché y no considerará el cambio reciente en WebElement.
Más sobre PageFactory.initElements ()
Ahora que entendemos la estrategia de Pagefactory para inicializar los elementos web usando InitElements (), intentemos comprender las diferentes versiones del método.
El método, como sabemos, toma el objeto controlador y el objeto de la clase actual como parámetros de entrada y devuelve el objeto de la página inicializando implícita y proactivamente todos los elementos de la página.
En la práctica, el uso del constructor como se muestra en la sección anterior es más preferible que las otras formas de uso.
Las formas alternativas de llamar al método son:
#1) En lugar de usar el puntero 'this', puede crear el objeto de clase actual, pasarle la instancia del controlador y llamar al método estático initElements con parámetros, es decir, el objeto controlador y el objeto de clase que acaba de crear.
|_+_|#2) La tercera forma de inicializar elementos usando la clase Pagefactory es usando la API llamada 'reflexión'. Sí, en lugar de crear un objeto de clase con una palabra clave 'nueva', classname.class se puede pasar como parte del parámetro de entrada initElements ().
|_+_|Preguntas frecuentes
P # 1) ¿Cuáles son las diferentes estrategias de localización que se utilizan para @FindBy?
Responder: La respuesta simple a esto es que no hay diferentes estrategias de localización que se utilicen para @FindBy.
Usan las mismas 8 estrategias de localización que usa el método findElement () en el POM habitual:
- identificación
- nombre
- nombre de la clase
- xpath
- css
- tagName
- Texto del enlace
- parcialLinkText
P # 2) ¿Existen diferentes versiones para el uso de las anotaciones @FindBy también?
Responder: Cuando hay un elemento web para buscar, usamos la anotación @FindBy. También explicaremos las formas alternativas de usar @FindBy junto con las diferentes estrategias de localización.
Ya hemos visto cómo usar la versión 1 de @FindBy:
|_+_|La versión 2 de @FindBy pasa el parámetro de entrada como Cómo y Usando .
Cómo busca la estrategia de localización mediante la cual se identificaría el elemento web. La palabra clave usando define el valor del localizador.
Vea a continuación para una mejor comprensión,
- How.ID busca el elemento usando identificación estrategia y el elemento que intenta identificar tiene id = cidkeyword.
- Cómo.CLASS_NAME busca el elemento usando nombre de la clase estrategia y el elemento que intenta identificar tiene clase = Nueva clase.
P # 3) ¿Hay alguna diferencia entre las dos versiones de @FindBy?
Responder: La respuesta es No, no hay diferencia entre las dos versiones. Es solo que la primera versión es más corta y fácil en comparación con la segunda versión.
P # 4) ¿Qué uso en la pagefactory en caso de que haya una lista de elementos web para ubicar?
Responder: En el patrón de diseño de objeto de página habitual, tenemos driver.findElements () para ubicar varios elementos que pertenecen a la misma clase o nombre de etiqueta, pero ¿cómo ubicamos dichos elementos en el caso del modelo de objeto de página con Pagefactory? La forma más fácil de lograr tales elementos es usar la misma anotación @FindBy.
Entiendo que esta línea parece ser un rasguño para muchos de ustedes. Pero sí, es la respuesta a la pregunta.
Veamos el siguiente ejemplo:
Usando el modelo de objeto de página habitual sin Pagefactory, usa driver.findElements para ubicar varios elementos como se muestra a continuación:
|_+_|Se puede lograr lo mismo utilizando el modelo de objetos de página con Pagefactory como se indica a continuación:
|_+_|Básicamente, asignar los elementos a una lista de tipo WebElement hace el truco independientemente de si se ha utilizado Pagefactory o no al identificar y localizar los elementos.
P # 5) ¿Se pueden usar tanto el diseño del objeto Page sin pagefactory como con Pagefactory en el mismo programa?
Responder: Sí, tanto el diseño del objeto de página sin Pagefactory como con Pagefactory se pueden utilizar en el mismo programa. Puede seguir el programa que se indica a continuación en el Respuesta a la pregunta 6 para ver cómo se utilizan ambos en el programa.
Una cosa para recordar es que el concepto de Pagefactory con la función de caché debe evitarse en elementos dinámicos, mientras que el diseño de objetos de página funciona bien para elementos dinámicos. Sin embargo, Pagefactory solo se adapta a elementos estáticos.
P # 6) ¿Existen formas alternativas de identificar elementos basados en múltiples criterios?
¿Qué capa del modelo osi funciona con marcos?
Responder: La alternativa para identificar elementos en base a múltiples criterios es usar las anotaciones @FindAll y @FindBys. Estas anotaciones ayudan a identificar elementos únicos o múltiples en función de los valores obtenidos de los criterios pasados en él.
# 1) @FindAll:
@FindAll puede contener varios @FindBy y devolverá todos los elementos que coincidan con cualquier @FindBy en una sola lista. @FindAll se usa para marcar un campo en un objeto de página para indicar que la búsqueda debe usar una serie de etiquetas @FindBy. A continuación, buscará todos los elementos que coincidan con cualquiera de los criterios de FindBy.
Tenga en cuenta que no se garantiza que los elementos estén en el orden del documento.
La sintaxis para usar @FindAll es la siguiente:
|_+_|Explicación: @FindAll buscará e identificará elementos separados que se ajusten a cada uno de los criterios de @FindBy y los enumerará. En el ejemplo anterior, primero buscará un elemento cuyo id = ”foo” y luego, identificará el segundo elemento con className = ”bar”.
Suponiendo que hubo un elemento identificado para cada criterio FindBy, @FindAll dará como resultado una lista de 2 elementos, respectivamente. Recuerde, podría haber múltiples elementos identificados para cada criterio. Así, en palabras simples, @ Encuentra todos actos equivalentes a la O operador en los criterios @FindBy pasados.
# 2) @FindBys:
FindBys se usa para marcar un campo en un objeto de página para indicar que la búsqueda debe usar una serie de etiquetas @FindBy en una cadena como se describe en ByChained. Cuando los objetos WebElement necesarios deben coincidir con todos los criterios dados, utilice la anotación @FindBys.
La sintaxis para usar @FindBys es la siguiente:
|_+_|Explicación: @FindBys buscará e identificará elementos que cumplan con todos los criterios de @FindBy y los enumerará. En el ejemplo anterior, buscará elementos cuyo nombre = ”foo” y className = ”bar”.
@FindAll dará como resultado una lista de 1 elemento si asumimos que hubo un elemento identificado con el nombre y el className en los criterios dados.
Si no hay un elemento que satisfaga todas las condiciones de FindBy aprobadas, el resultado de @FindBys será cero elementos. Podría haber una lista de elementos web identificados si todas las condiciones satisfacen varios elementos. En palabras simples, @ FindBys actos equivalentes a la Y operador en los criterios @FindBy pasados.
Veamos la implementación de toda la anotación anterior a través de un programa detallado:
Modificaremos el programa www.nseindia.com dado en la sección anterior para comprender la implementación de las anotaciones @FindBy, @FindBys y @FindAll
# 1) El repositorio de objetos de PagefactoryClass se actualiza de la siguiente manera:
Lista newlist = driver.findElements (By.tagName ('a'));
@FindBy (cómo = Cómo. TAG_NAME , usando = 'a')
privado Lista findbyvalue;
@Encuentra todos ({ @FindBy (className = 'sel'), @FindBy (xpath = ”// a (@ id =’ tab5 ′) ”)})
privado Lista findallvalue;
@FindBys ({ @FindBy (className = 'sel'), @FindBy (xpath = ”// a (@ id =’ tab5 ′) ”)})
privado Lista de findbysvalue;
# 2) Se escribe un nuevo método seeHowFindWorks () en PagefactoryClass y se invoca como último método en la clase Main.
El método es el siguiente:
|_+_|A continuación se muestra el resultado que se muestra en la ventana de la consola después de la ejecución del programa:
Intentemos ahora entender el código en detalle:
#1) A través del patrón de diseño del objeto de la página, el elemento 'lista nueva' identifica todas las etiquetas con el ancla 'a'. En otras palabras, obtenemos un recuento de todos los enlaces de la página.
Aprendimos que pagefactory @FindBy hace el mismo trabajo que driver.findElement (). El elemento findbyvalue se crea para obtener el recuento de todos los enlaces de la página mediante una estrategia de búsqueda que tiene un concepto de pagefactory.
Resulta correcto que tanto driver.findElement () como @FindBy hagan el mismo trabajo e identifiquen los mismos elementos. Si observa la captura de pantalla de la ventana de la consola resultante, el recuento de enlaces identificados con el elemento newlist y el de findbyvalue son iguales, es decir, 299 enlaces que se encuentran en la página.
El resultado se muestra a continuación:
|_+_|#2) Aquí explicamos el funcionamiento de la anotación @FindAll que pertenecerá a la lista de elementos web con el nombre findallvalue.
Observando atentamente cada criterio @FindBy dentro de la anotación @FindAll, el primer criterio @FindBy busca elementos con className = 'sel' y el segundo criterio @FindBy busca un elemento específico con XPath = “// a (@ id = 'tab5')
Ahora presionemos F12 para inspeccionar los elementos en la página nseindia.com y obtener cierta claridad sobre los elementos correspondientes a los criterios @FindBy.
Hay dos elementos en la página correspondientes a className = ”sel”:
a) El elemento 'Fundamentos' tiene la etiqueta de lista, es decir
Ver instantánea a continuación
b) Otro elemento 'Libro de pedidos' tiene un XPath con una etiqueta de anclaje que tiene el nombre de la clase como 'sel'.
c) El segundo @FindBy con XPath tiene una etiqueta de ancla cuya identificación es ' tab5 ”. Solo hay un elemento identificado en respuesta a la búsqueda que es Fundamentos.
Vea la instantánea a continuación:
Cuando se ejecutó la prueba nseindia.com, obtuvimos el recuento de elementos buscados por.
@FindAll as 3. Los elementos para findallvalue cuando se muestran fueron: Fundamentals as the 0thelemento de índice, Libro de pedidos como el 1S telemento de índice y Fundamentos nuevamente como el 2Dakota del Norteelemento de índice. Ya aprendimos que @FindAll identifica elementos para cada criterio @FindBy por separado.
Según el mismo protocolo, para la búsqueda del primer criterio, es decir, className = 'sel', identificó dos elementos que cumplían la condición y obtuvo 'Fundamentos' y 'Libro de pedidos'.
Luego se movió al siguiente criterio @FindBy y según el xpath dado para el segundo @FindBy, podría obtener el elemento 'Fundamentos'. Por eso, finalmente identificó 3 elementos, respectivamente.
Por lo tanto, no obtiene los elementos que satisfacen ninguna de las condiciones de @FindBy, sino que trata por separado cada una de las @FindBy e identifica los elementos de la misma manera. Además, en el ejemplo actual, también vimos que no observa si los elementos son únicos ( P.ej. El elemento 'Fundamentos' en este caso que se muestra dos veces como parte del resultado de los dos criterios @FindBy)
#3) Aquí elaboramos sobre el funcionamiento de la anotación @FindBys que pertenecerá a la lista de elementos web con el nombre findbysvalue. Aquí también, el primer criterio @FindBy busca elementos con className = ’sel’ y el segundo criterio @FindBy busca un elemento específico con xpath = '// a (@ id =' tab5 ').
Ahora que lo sabemos, los elementos identificados para la primera condición de @FindBy son “Fundamentals” y “Order Book” y el del segundo criterio de @FindBy es “Fundamentals”.
Entonces, ¿cómo será el resultado de @FindBys diferente al de @FindAll? Aprendimos en la sección anterior que @FindBys es equivalente al operador condicional AND y, por lo tanto, busca un elemento o la lista de elementos que satisfaga toda la condición @FindBy.
Según nuestro ejemplo actual, el valor 'Fundamentals' es el único elemento que tiene class = 'sel' e id = 'tab5', satisfaciendo ambas condiciones. Es por esto que el tamaño de @FindBys en nuestro caso de prueba es 1 y muestra el valor como 'Fundamentos'.
Almacenamiento en caché de los elementos en Pagefactory
Cada vez que se carga una página, todos los elementos de la página se vuelven a buscar invocando una llamada a través de @FindBy o driver.findElement () y hay una nueva búsqueda de los elementos de la página.
La mayoría de las veces, cuando los elementos son dinámicos o cambian constantemente durante el tiempo de ejecución, especialmente si son elementos AJAX, ciertamente tiene sentido que con cada carga de página haya una nueva búsqueda de todos los elementos de la página.
Cuando la página web tiene elementos estáticos, almacenar en caché el elemento puede ayudar de varias formas. Cuando los elementos se almacenan en caché, no es necesario que vuelva a ubicarlos al cargar la página, sino que puede hacer referencia al repositorio de elementos en caché. Esto ahorra mucho tiempo y mejora el rendimiento.
Pagefactory proporciona esta función de almacenar en caché los elementos mediante una anotación @CacheLookUp .
La anotación le dice al controlador que use la misma instancia del localizador del DOM para los elementos y que no vuelva a buscarlos, mientras que el método initElements de pagefactory contribuye de manera prominente a almacenar el elemento estático en caché. InitElements realiza el trabajo de almacenamiento en caché de los elementos.
Esto hace que el concepto de pagefactory sea especial sobre el patrón de diseño de objeto de página normal. Viene con sus propios pros y contras que discutiremos un poco más adelante. Por ejemplo, el botón de inicio de sesión en la página de inicio de Facebook es un elemento estático, que se puede almacenar en caché y es un elemento ideal para almacenar en caché.
Veamos ahora cómo implementar la anotación @CacheLookUp
Primero deberá importar un paquete para Cachelookup como se muestra a continuación:
|_+_|A continuación se muestra el fragmento que muestra la definición de un elemento usando @CacheLookUp. Tan pronto como se busca en UniqueElement por primera vez, initElement () almacena la versión en caché del elemento para que la próxima vez que el controlador no busque el elemento, se refiera a la misma caché y realice la acción en el elemento correcto lejos.
|_+_|Veamos ahora a través de un programa real de cómo las acciones en el elemento web almacenado en caché son más rápidas que en el elemento web no almacenado en caché:
Mejorando aún más el programa nseindia.com, he escrito otro método nuevo monitorPerformance () en el que creo un elemento en caché para el cuadro de búsqueda y un elemento no en caché para el mismo cuadro de búsqueda.
Luego trato de obtener el nombre de etiqueta del elemento 3000 veces tanto para el elemento almacenado en caché como para el no almacenado en caché y trato de medir el tiempo que tarda el elemento almacenado en caché y el elemento no almacenado en caché para completar la tarea.
Lo he considerado 3000 veces para que podamos ver una diferencia visible en los tiempos de los dos. Esperaré que el elemento almacenado en caché complete la obtención del nombre de etiqueta 3000 veces en menos tiempo en comparación con el del elemento no almacenado en caché.
Ahora sabemos por qué el elemento almacenado en caché debería funcionar más rápido, es decir, se le indica al controlador que no busque el elemento después de la primera búsqueda sino que continúe trabajando directamente en él y ese no es el caso con el elemento no almacenado en caché donde se realiza la búsqueda del elemento. las 3000 veces y luego se realiza la acción en él.
A continuación se muestra el código para el método monitorPerformance ():
|_+_|En la ejecución, veremos el siguiente resultado en la ventana de la consola:
Según el resultado, la tarea en el elemento no almacenado en caché se completa en 82 segundos, mientras que el tiempo necesario para completar la tarea en el elemento en caché fue solo 37 segundos. De hecho, esta es una diferencia visible en el tiempo de respuesta tanto del elemento almacenado en caché como del no almacenado en caché.
P # 7) ¿Cuáles son los pros y los contras de la anotación @CacheLookUp en el concepto de Pagefactory?
Responder:
Pros @CacheLookUp y situaciones factibles para su uso:
@CacheLookUp es factible cuando los elementos son estáticos o no cambian en absoluto mientras se carga la página. Estos elementos no cambian el tiempo de ejecución. En tales casos, es aconsejable utilizar la anotación para mejorar la velocidad general de ejecución de la prueba.
Contras de la anotación @CacheLookUp:
La mayor desventaja de tener elementos almacenados en caché con la anotación es el temor de obtener StaleElementReferenceExceptions con frecuencia.
Los elementos dinámicos se actualizan con bastante frecuencia con aquellos que son susceptibles de cambiar rápidamente durante unos segundos o minutos del intervalo de tiempo.
A continuación se muestran algunos de estos casos de elementos dinámicos:
- Tener un cronómetro en la página web que mantiene el temporizador actualizándose cada segundo.
- Un marco que actualiza constantemente el informe meteorológico.
- Una página que informa las actualizaciones de Sensex en vivo.
Estos no son ideales ni factibles para el uso de la anotación @CacheLookUp en absoluto. Si lo hace, corre el riesgo de obtener la excepción de StaleElementReferenceExceptions.
Al almacenar en caché dichos elementos, durante la ejecución de la prueba, el DOM de los elementos cambia; sin embargo, el controlador busca la versión de DOM que ya estaba almacenada durante el almacenamiento en caché. Esto hace que el controlador busque el elemento obsoleto que ya no existe en la página web. Esta es la razón por la que se lanza StaleElementReferenceException.
Clases de fábrica:
Pagefactory es un concepto construido sobre múltiples clases e interfaces de fábrica. Aprenderemos sobre algunas clases e interfaces de fábrica aquí en esta sección. Algunos de los que veremos son AjaxElementLocatorFactory , ElementLocatorFactory y DefaultElementFactory.
¿Nos hemos preguntado alguna vez si Pagefactory proporciona alguna forma de incorporar la espera implícita o explícita del elemento hasta que se cumpla una determinada condición ( Ejemplo: Hasta que un elemento esté visible, habilitado, cliqueable, etc.)? Si es así, aquí hay una respuesta adecuada.
AjaxElementLocatorFactory es uno de los contribuyentes importantes entre todas las clases de fábricas. La ventaja de AjaxElementLocatorFactory es que puede asignar un valor de tiempo de espera para un elemento web a la clase de página Objeto.
Aunque Pagefactory no proporciona una función de espera explícita, existe una variante de la espera implícita usando la clase AjaxElementLocatorFactory . Esta clase se puede utilizar incorporada cuando la aplicación utiliza componentes y elementos Ajax.
Así es como se implementa en el código. Dentro del constructor, cuando usamos el método initElements (), podemos usar AjaxElementLocatorFactory para proporcionar una espera implícita en los elementos.
|_+_|La segunda línea anterior del código implica que el controlador establecerá un tiempo de espera de 20 segundos para todos los elementos de la página cuando se cargue cada uno de sus elementos y si alguno de los elementos no se encuentra después de una espera de 20 segundos, se lanza 'NoSuchElementException' para ese elemento que falta.
También puede definir la espera de la siguiente manera:
|_+_|El código anterior funciona perfectamente porque la clase AjaxElementLocatorFactory implementa la interfaz ElementLocatorFactory.
Aquí, la interfaz principal (ElementLocatorFactory) se refiere al objeto de la clase secundaria (AjaxElementLocatorFactory). Por lo tanto, el concepto de Java de 'upcasting' o 'polimorfismo en tiempo de ejecución' se utiliza al asignar un tiempo de espera mediante AjaxElementLocatorFactory.
Con respecto a cómo funciona técnicamente, AjaxElementLocatorFactory primero crea un AjaxElementLocator usando un SlowLoadableComponent que podría no haber terminado de cargarse cuando el load () regresa. Después de una llamada a load (), el método isLoaded () debería seguir fallando hasta que el componente se haya cargado por completo.
En otras palabras, todos los elementos se buscarán de nuevo cada vez que se acceda a un elemento en el código invocando una llamada a locator.findElement () desde la clase AjaxElementLocator que luego aplica un tiempo de espera hasta que se cargue a través de la clase SlowLoadableComponent.
Además, después de asignar el tiempo de espera a través de AjaxElementLocatorFactory, los elementos con la anotación @CacheLookUp ya no se almacenarán en caché porque la anotación se ignorará.
También hay una variación de cómo usted puede llama a initElements () método y cómo no debería llama a AjaxElementLocatorFactory para asignar tiempo de espera a un elemento.
# 1) También puede especificar un nombre de elemento en lugar del objeto controlador como se muestra a continuación en el método initElements ():
|_+_|El método initElements () en la variante anterior invoca internamente una llamada a la clase DefaultElementFactory y el constructor de DefaultElementFactory acepta el objeto de la interfaz SearchContext como parámetro de entrada. El objeto de controlador web y un elemento web pertenecen a la interfaz SearchContext.
En este caso, el método initElements () se inicializará por adelantado solo en el elemento mencionado y no se inicializarán todos los elementos de la página web.
#2) Sin embargo, aquí hay un giro interesante a este hecho que establece cómo no debe llamar al objeto AjaxElementLocatorFactory de una manera específica. Si utilizo la variante anterior de initElements () junto con AjaxElementLocatorFactory, fallará.
Ejemplo: El siguiente código, es decir, pasar el nombre del elemento en lugar del objeto del controlador a la definición de AjaxElementLocatorFactory no funcionará, ya que el constructor de la clase AjaxElementLocatorFactory solo toma el objeto del controlador web como parámetro de entrada y, por lo tanto, el objeto SearchContext con el elemento web no funcionaría para él.
|_+_|P # 8) ¿El uso de pagefactory es una opción viable sobre el patrón de diseño de objeto de página normal?
Responder: Esta es la pregunta más importante que tiene la gente y por eso pensé en abordarla al final del tutorial. Ahora conocemos las entradas y salidas de Pagefactory a partir de sus conceptos, las anotaciones utilizadas, las funciones adicionales que admite, la implementación a través del código, los pros y los contras.
Sin embargo, nos quedamos con esta pregunta esencial de que si pagefactory tiene tantas cosas buenas, ¿por qué no seguir con su uso?
Pagefactory viene con el concepto de CacheLookUp que vimos que no es factible para elementos dinámicos como los valores del elemento que se actualizan con frecuencia. Entonces, pagefactory sin CacheLookUp, ¿es una buena opción para comenzar? Sí, si los xpaths son estáticos.
Sin embargo, la desventaja es que la aplicación de la era moderna está llena de elementos dinámicos pesados donde sabemos que el diseño del objeto de página sin pagefactory funciona bien en última instancia, pero ¿el concepto de pagefactory funciona igualmente bien con xpaths dinámicos? Tal vez no. Aquí hay un ejemplo rápido:
En la página web nseindia.com, vemos una tabla como se muestra a continuación.
El xpath de la tabla es
|_+_|Queremos recuperar los valores de cada fila para la primera columna 'Cantidad de compra'. Para hacer esto, necesitaremos incrementar el contador de filas, pero el índice de la columna seguirá siendo 1. No hay forma de que podamos pasar este XPath dinámico en la anotación @FindBy, ya que la anotación acepta valores que son estáticos y no se puede pasar ninguna variable. eso.
Aquí es donde la pagefactory falla por completo mientras que el POM habitual funciona muy bien con ella. Puede usar fácilmente un bucle for para incrementar el índice de fila usando tales xpaths dinámicos en el método driver.findElement ().
Conclusión
Page Object Model es un concepto o patrón de diseño utilizado en el marco de automatización de Selenium.
La denominación de convección de métodos es fácil de usar en el Modelo de objetos de página. El Código en POM es fácil de entender, reutilizable y mantenible. En POM, si hay algún cambio en el elemento web, es suficiente con realizar los cambios en su clase respectiva, en lugar de editar todas las clases.
Pagefactory, al igual que el POM habitual, es un concepto maravilloso de aplicar. Sin embargo, necesitamos saber dónde es factible el POM habitual y dónde encaja bien Pagefactory. En las aplicaciones estáticas (donde tanto XPath como los elementos son estáticos), Pagefactory se puede implementar generosamente con beneficios adicionales de un mejor rendimiento también.
Alternativamente, cuando la aplicación involucra elementos dinámicos y estáticos, puede tener una implementación mixta del pom con Pagefactory y sin Pagefactory según la viabilidad de cada elemento web.
Autor: Este tutorial ha sido escrito por Shobha D. Ella trabaja como líder de proyecto y cuenta con más de 9 años de experiencia en pruebas manuales, de automatización (Selenium, IBM Rational Functional Tester, Java) y API (SOAPUI y Tenga la seguridad en Java) .
Ahora le toca a usted, para una mayor implementación de Pagefactory.
Feliz Exploración !!!
=> Visite aquí para aprender el selenio desde cero.
Lectura recomendada
- Más de 30 mejores tutoriales de selenio: aprenda selenio con ejemplos reales
- Scripts eficientes de Selenium y escenarios de resolución de problemas: tutorial de Selenium n. ° 27
- Depuración de scripts de Selenium con registros (Tutorial de Log4j) - Tutorial de Selenium n. ° 26
- Introducción a JUnit Framework y su uso en Selenium Script - Tutorial de Selenium n. ° 11
- 7 factores que afectan la estimación de prueba del proyecto de automatización de selenio - Tutorial de selenio n. ° 32
- Afirmaciones en Selenium usando marcos Junit y TestNG
- Cómo usar TestNG Framework para crear scripts de Selenium - Tutorial de TestNG Selenium n. ° 12
- Aprenda a usar las anotaciones de TestNG en Selenium (con ejemplos)