Automatización con Codeception + Gherkin + PageObject para los más pequeños


Al no haber encontrado un solo ejemplo concreto de una implementación de Gherkin con un patrón de diseño de Objeto de página para Codeception en Internet , pensé que no estaría fuera de lugar decirle a Internet sobre nuestra propia implementación de este patrón.

Este artículo está destinado más a aquellos que ya están un poco familiarizados con Codeception o marcos similares, pero aún no saben cómo usar Test Object para hacer que las pruebas sean más legibles, simplificar su soporte y reducir la cantidad de código adicional. Sin embargo, intenté explicar paso a paso todos los puntos principales del ensamblaje del proyecto de automatización desde cero.

La plantilla Objeto de página le permite encapsular el trabajo con elementos de página, lo que a su vez le permite reducir la cantidad de código y simplificar su soporte. Todos los cambios en la interfaz de usuario se implementan fácil y rápidamente: solo actualice la clase de objeto de página que describe esta página. Otra ventaja importante de este enfoque arquitectónico es que le permite no saturar el script de prueba HTML con detalles, lo que lo hace más comprensible y fácil de entender.

Así es como se ve la prueba sin usar Page Object



Usar objeto de página



No me detendré en instalar el entorno básico, daré mis datos iniciales:

  • Ubuntu bionic beaver
  • PHP 7.1.19-1
  • Compositor: administrador de gestión de dependencias para PHP, instalado globalmente
  • PhpStorm - entorno de desarrollo

Para ejecutar las pruebas, también necesitamos:


Expandir Codeception


Proceda a instalar Codeception:

Abrimos en el terminal el directorio que necesitamos, donde recopilaremos el proyecto, o crearemos un directorio para el proyecto e iremos a él:

mkdir ProjectTutorial cd ProjectTutorial 

Instale el marco de Codeception y sus dependencias:

 composer require codeception/codeception --dev 



El archivo de instalación de dependencia composer.json en el proyecto se verá así:

 { "require": { "php": ">=5.6.0 <8.0", "facebook/webdriver": ">=1.1.3 <2.0", "behat/gherkin": "^4.4.0", "codeception/phpunit-wrapper": "^6.0.9|^7.0.6" }, "require-dev": { "codeception/codeception": "^2.5", "codeception/base": "^2.5" } } 

Expande el proyecto:

 php vendor/bin/codecept bootstrap 



Puede encontrar más información sobre cómo instalar el proyecto en la documentación oficial .

En esta etapa, se crean tres conjuntos de pruebas en nuestro proyecto. Por defecto, Codeception los divide en aceptación, funcional y unidad. Para estos conjuntos, Codeception también genera tres archivos yml. En ellas indicamos todas las configuraciones necesarias, conectamos los módulos y propiedades para ejecutar nuestras pruebas.

Esta lección se basa en el ejemplo de la prueba de aceptación, por lo que daré la configuración en Acceptance.suite.yml.

Abra nuestro proyecto en PHP Storm (u otro entorno de desarrollo favorito) y vaya a Acceptance.suite.yml (de forma predeterminada, se encuentra en la carpeta tests / accept.suite.yml).
Anotamos las dependencias mínimas necesarias y siempre prestamos atención al formateo. Los módulos están separados por un signo "-" y deben estar en el mismo nivel; de lo contrario, los errores aparecerán cuando comience la prueba.

Resulta que:

 actor: AcceptanceTester modules: enabled: - WebDriver: url: 'http://yandex.ru/' //    ,        browser: 'chrome' - \Helper\Acceptance //          gherkin: contexts: default: - AcceptanceTester 

Y algo más de trabajo preparatorio:

Cree un directorio separado en la raíz del proyecto (tengo lib).
En este directorio, cree el archivo ejecutable run.sh, que ejecutará Selenium y Chrome Driver.

Ponemos Selenium y Chrome Driver aquí, y escribimos el comando de ejecución en run.sh:

 java -jar -Dwebdriver.chrome.driver=chromedriver_241 selenium-server-standalone-3.14.0.jar 

Cómo se ve en el proyecto:



Regresamos a la consola y cambiamos los derechos de acceso:

 chmod +x ./run.sh 

(nota. Los nombres de los controladores que se encuentran en el directorio deben coincidir exactamente con los especificados en el comando de inicio).

Puede iniciar Selenium y Webdriver ahora mismo para no volver a esto. Para hacer esto, abra una nueva pestaña de terminal, vaya al directorio donde se encuentra el archivo run.sh y escriba el comando de inicio:

 ~/AutomationProjects/ProjectTutorial/lib$ ./run.sh 

Asegúrese de que el servidor se esté ejecutando:



Lo dejamos en un estado de ejecución. En este trabajo preparatorio se completa.

Escribir un guion de prueba


Procedemos a crear un archivo de características para nuestro caso de prueba. Para hacer esto, se proporciona un comando especial en Codeception, ejecútelo en la consola:

 cept g:feature acceptance check 

(nota "comprobar" - el nombre de mi prueba)

Vemos el nuevo archivo check.feature en la carpeta de aceptación.



No necesitamos el contenido predeterminado, lo eliminamos inmediatamente y escribimos nuestra prueba.

Para que el coleccionista reconozca el alfabeto cirílico, no olvide comenzar el guión con #language: ru.
Estamos escribiendo un guión corto en ruso. Le recuerdo que cada oración debe comenzar con las palabras clave: "Cuándo", "Entonces", "Y", el símbolo "*", etc.

Para mi ejemplo, tomé el sitio web de Yandex, puedes tomar cualquiera.



Para ver qué pasos hay en la prueba, ejecutamos nuestro script en la terminal:

 cept dry-run acceptance check.feature 



Los pasos del script se muestran en la consola, pero su implementación aún no está disponible.

Luego ejecutamos un comando que generará automáticamente plantillas para implementar nuestros métodos:

 cept gherkin:snippets acceptance 



Todos los nombres del script que estaban entre comillas se reemplazan con variables: arg.
Los copiamos del terminal y los pegamos en el archivo AcceptanceTester.php , donde se encontrarán los métodos para trabajar con elementos de página.



Cambie el nombre de los métodos a legibles, reflejando su esencia (opcional), y escriba su implementación.



Todo es simple, pero aún más simple si está trabajando en un entorno de desarrollo inteligente, como Storm, que a su vez solicitará los comandos necesarios de la biblioteca:



Eliminamos el exceso y escribimos los métodos:

 /** * @When      */ public function step_beingOnMainPage($page) { $this->amOnPage('/'); } /** * @Then    :element */ public function step_seeElement($element) { this->seeElement($element); } /** * @Then    :button */ public function step_clickOnButton($button) { $this->click($button); } /** * @Then    :field  :text */ public function step_fillField($field, $text) { $this->fillField($field, $text); } 

Veamos que pasó. Lanzamos un equipo que nos mostrará qué métodos (paso) ahora tenemos una implementación.

 cept gherkin:steps acceptance 



Éxito!

Pero los pasos en el archivo de características aún no se reconocen como métodos.



Para que Storm comprenda qué hacer con los pasos, haremos un truco con la implementación de la interfaz Context desde el espacio de nombres Gherkin Context.

 namespace Behat\Behat\Context { interface Context {} } 

Envuelva nuestra clase AcceptanceTester en el espacio de nombres y herede de Context

 implements \Behat\Behat\Context\Context 



Ahora todos los pasos del archivo de características están vinculados a su implementación:



Para que Webdriver entienda en qué hacer clic y dónde buscar, debe reemplazar los nombres de elementos legibles y las direcciones de página con los correspondientes localizadores y URL, que se incluirán en los métodos como argumentos.

Luego obtenemos una prueba de la forma:



Y puedes correr:

 cept run acceptance 



Pasado

aprox. Si los elementos de la página tardan mucho en cargarse, puede agregar la espera al método deseado:

 $this->waitForElementVisible($element); 

Regresamos a nuestro escenario de prueba. Estamos molestos porque toda la legibilidad de la prueba se pierde debido al hecho de que en lugar de los nombres claros de los elementos y páginas, vemos elementos HTML y URL.

Si queremos solucionar esto, es hora de pasar a la implementación del patrón Objeto de página.

Ir al objeto de página


En el directorio _support, cree el directorio de la página, donde colocaremos nuestras páginas de clase:

 php vendor/bin/codecept generate:pageobject MainPage 

El primer objeto de página es la página principal de Yandex, llamémosla MainPage, llamaremos a la clase de la misma manera:



Aquí declaramos campos y métodos estáticos para que puedan llamarse sin crear un objeto.

Como en las configuraciones de Acceptance.suite.yml ya especificamos la url de la página de inicio: yandex.ru , para la página principal será suficiente especificar

 public static $URL = '/'; 

Luego viene un conjunto de elementos de página. Describimos localizadores para varios elementos y les damos nombres claros y únicos.

Ahora necesita agregar el método getElement, que devolverá el localizador por el nombre del elemento de la matriz.

Como resultado, tenemos:

 <?php //location: tests/_support/Page/MainPage.php namespace Page; /**   */ class MainPage { public static $URL = '/'; public static $elements = array( ' ' => "//*[@id='wd-wrapper-_afisha']", ' ' => "//*[@data-statlog='afisha.title.link']", ' ' => "//*[@class='weather__icon weather__icon_ovc']|//*[@class='weather__icon weather__icon_skc_d']", ); public static function getElement($name){ return self::$elements[$name]; } } 

Agregue un par de clases de página:

/ ** Cartel * /



/ ** Poster - Resultados de búsqueda * /



Regresamos a la clase AcceptanceTester.php , donde escribimos nuestros métodos.
Creemos en él una matriz de clases de PageObject, donde asignaremos los nombres a las páginas e indicaremos sus nombres de clase en el espacio de nombres:

  private $pages = array( " " => "\Page\MainPage", "" => "\Page\AfishaPage", " -  " => "\Page\AfishaResult" ); 

Cada nuevo PageObject se agrega de manera similar a esta matriz.

A continuación, debemos crear el campo página actual, que almacenará el enlace al objeto de página de la página actual:

 private $currentPage; 

Ahora escribiremos un método, cuando se lo llame, podemos obtener currentPage e inicializar la clase PageObject que necesitamos.

Es lógico dar un paso como este utilizando el método "Cuando el usuario navega a la página" Nombre de la página ". Entonces, la forma más simple de inicializar la clase PageObject, sin controles, se vería así:

 /** * @When     :page */ public function step_beingOn($page) { //   pageObject $this->currentPage = $this->pages[$page]; } 

Ahora escribimos el método getPageElement, que nos permitirá obtener el elemento, o más bien, su localizador desde la página actual:

 private function getPageElement($elementName) { //         $curPage = $this->currentPage; return $curPage::getElement($elementName); } 



Para los métodos ya implementados, es necesario reemplazar los argumentos que recibimos directamente del texto de la característica al principio con elementos de PageObject, es decir:

 $arg 

tomará la forma

 getPageElement($arg)) 

Entonces nuestros métodos tomarán la forma:

 /** * @When     :page */ public function step_beingOnMainPage($page) { //      pageObject $this->currentPage = $this->pages[$page]; $curPage = $this->currentPage; $this->amOnPage($curPage::$URL); } /** * @Then    :element */ public function step_seeElement($element) { $this->waitForElementVisible($this->getPageElement($element)); $this->seeElement($this->getPageElement($element)); } /** * @Then    :button */ public function step_clickOnButton($button) { $this->click($this->getPageElement($button)); } /** * @Then    :field  :text */ public function step_fillField($field, $text) { $this->fillField($this->getPageElement($field), $text); } /** * @Then      :field */ public function step_deleteText($field) { $this->clearField($this->getPageElement($field)); } 

Se agregó otro método para mostrar los resultados de búsqueda presionando Enter:

 /** * @Then    ENTER */ public function step_keyboardButton() { $this->pressKey('//input',WebDriverKeys::ENTER); } 

El último paso es cuando se describen todos los métodos y PageObjects necesarios, debe refactorizar la prueba en sí. Agregue los pasos que inicializarán PageObject cuando vaya a una página nueva. Tenemos este "* usuario fue a la página: página".

Para mayor claridad, agregaré algunos pasos más. El resultado es esta prueba:

 #language: ru :     :   .    .   .      " "     " "     " "     " "      ""     " "  " "     ENTER      " -  "     "   "       " "     " "  ""     ENTER 

Tal escenario de prueba es comprensible y legible para cualquier extraño.

Lanzamiento

Para ver un resultado de ejecución más detallado, puede usar el comando

 cept run acceptance --debug 

Nos fijamos en el resultado:



Por lo tanto, el uso del patrón Objeto de página le permite separar todos los elementos de página de los scripts de prueba y almacenarlos en un directorio separado.

El proyecto en sí se puede encontrar en https://github.com/Remneva/ProjectTutorial

Como ingeniero de automatización principiante, le agradeceré que comparta sus ideas y, tal vez, me diga cómo transformar y simplificar la estructura del proyecto de la forma más lógica posible.

Source: https://habr.com/ru/post/es427031/


All Articles