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:
public function step_beingOnMainPage($page) { $this->amOnPage('/'); } public function step_seeElement($element) { this->seeElement($element); } public function step_clickOnButton($button) { $this->click($button); } 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:
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/ProjectTutorialComo 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.