10/04/2018 | Consejos tecnológicos,Desarrollo de aplicaciones,Tecnologías

Pruebas extremo a extremo en Angular con Cucumber

Si preguntamos a un grupo de 10 desarrolladores “¿Cómo probáis todas las funcionalidades de vuestras aplicaciones?”, es muy probable que la mitad de ellos respondan con: “Es muy simple, lanzo la aplicación y hago esas comprobaciones a mano”. Todos hemos realizado esta práctica en algún momento, ya que es muy común durante el proceso de desarrollo. No obstante, sabiendo esa respuesta, si ahora preguntamos “¿Pero también compruebas, al incluir una nueva funcionalidad, que todas las anteriores sigan funcionando correctamente?”, la cosa cambia mucho pues es algo que no se suele realizar, con lo cual aumenta la probabilidad de que aparezcan incidencias de regresión. En el caso de una aplicación basada en Angular, cuanto más crece dicha aplicación, mayor es la relación entre sus componentes, servicios y vistas, por lo que al realizar cualquier cambio en un método, por pequeño que sea, debemos cerciorarnos de que funciona en todas y cada una de las partes de la aplicación que lo utilizan. Evidentemente si realizamos todas estas comprobaciones a mano, el tiempo y esfuerzo de mantenimiento del proyecto puede llegar a ser muy alto.

Por suerte para estos desarrolladores, existen herramientas y tecnologías que nos ayudan a realizar estas comprobaciones de forma automática. Algunas de estas tecnologías son Protractor, un entorno donde realizar pruebas E2E (extremo a extremo, del inglés «End-to-End») y Cucumber, el lenguaje con el que escribiremos esas pruebas.

En Tribalyte estamos comprometidos a entregar productos de la máxima calidad, y una de las maneras de asegurar dicha calidad de manera efectiva es utilizar este (y otros) tipo de pruebas automatizadas, que además son fácilmente integrables en ciclos de integración continua (CI). En las siguientes líneas vamos a mostrar un ejemplo básico.

Si tenemos la suerte de comenzar un proyecto con Angular-CLI; Karma, Protractor y Jasmine vienen por defecto incluidos en él. Karma es también un entorno de ejecución de pruebas, en este caso para pruebas unitarias; y Jasmine es otro lenguaje para codificar dichas pruebas, pero para este artículo nos centraremos en Cucumber, ya que permite escribir estas pruebas en lenguaje natural, lo que las hacen muy fáciles de comprender.

Para comenzar, necesitamos iniciar un proyecto de Node.js y tener un archivo «package.json» operativo. En este, instalamos los siguientes paquetes:

 npm install --save-dev protractor cucumber protractor-cucumber-framework chai chai-as-promised<br />


Una vez instalados, nos cercioramos de que estén incluidos en el el apartado “devDependencies” del archivo «package.json».

Tras esto, necesitamos un archivo de configuración que permita a las pruebas acceder a todos los datos necesarios. Para ello, creamos un archivo “protractor.conf.js” en la raíz del proyecto. En él escribimos el siguiente código:

module.exports.config = {
    framework: &amp;amp;amp;amp;amp;#039;custom&amp;amp;amp;amp;amp;#039;,
    frameworkPath: &amp;amp;amp;amp;amp;#039;node_modules/protractor-cucumber-framework&amp;amp;amp;amp;amp;#039;,
    cucumberOpts: {
        require: [&amp;amp;amp;amp;amp;#039;steps/*.steps.js&amp;amp;amp;amp;amp;#039;],
        strict: true
    },
    specs: [&amp;amp;amp;amp;amp;#039;features/*.feature&amp;amp;amp;amp;amp;#039;],
    capabilities: {
        browserName: &amp;amp;amp;amp;amp;#039;chrome&amp;amp;amp;amp;amp;#039;,
    }
};

De este archivo destacamos:

  • Framework: Desde la versión 3.0 de Protractor, Cucumber no viene incluido por defecto, así que necesitamos del flag “custom” para añadirlo por nuestra cuenta.
  • FrameworkPath: En este punto añadimos el framework necesario, en este caso, “protractor-cucumber-framework”.
  • CucumberOpts: Aquí indicamos la carpeta en la que incluiremos el código de las pruebas a realizar; todas ellas en archivos que acaben en “.steps.js”.
  • Specs: Parecido al punto anterior, en este indicamos la carpeta que incluirá los archivos que enuncian, en lenguaje natural, las pruebas a realizar; todas ellas acabadas en “.feature”.
  • Capabilities: Necesitamos de un navegador en el que se realicen las pruebas, así que aquí indicamos cuál será. Por conveniencia, el más indicado es “Chrome”.

Para comenzar a realizar nuestras pruebas automatizadas, necesitamos de un archivo “.feature” en el que enunciaremos esas pruebas que pretendemos realizar. Este punto es exclusivo de Cucumber. Para que cualquiera pueda realizar estas pruebas, en el siguiente ejemplo las haremos sobre la página principal de Angular: https://angular.io/. En caso de que se quisieran realizar sobre una aplicación en desarrollo, no hay que olvidar iniciar un servidor local que permita navegar a la dirección necesaria (habitualmente «localhost»).

Creamos, en la carpeta “/features”, un archivo “example.feature” con el siguiente código:

Feature: Example
 Scenario: should navigate to the main page
   When I navigate to &amp;amp;amp;amp;amp;amp;amp;quot;https://angular.io/&amp;amp;amp;amp;amp;amp;amp;quot;
   Then the title should be &amp;amp;amp;amp;amp;amp;amp;quot;Angular&amp;amp;amp;amp;amp;amp;amp;quot;

Scenario: should be able to see the Docs page
   When I navigate to &amp;amp;amp;amp;amp;amp;amp;quot;https://angular.io/&amp;amp;amp;amp;amp;amp;amp;quot;
   When I click the Docs button
   Then I should see a &amp;amp;amp;amp;amp;amp;amp;quot;What is Angular?&amp;amp;amp;amp;amp;amp;amp;quot; article

Como se ha explicado anteriormente, Cucumber destaca en la facilidad que proporciona para entender los pasos a realizar en cada prueba, gracias al uso de lenguaje natural. Cada “Scenario” es una prueba, que contiene pasos que, de realizarse correctamente, confirmarán el correcto funcionamiento del sistema. Cada paso puede venir precedido de las palabras “When”, “Given” y “Then”; donde:

  • When precederá a una acción.
  • Given precederá a un estado en el que queremos que se encuentre la aplicación (precondiciones).
  • Then precederá a un resultado que esperamos.

Ahora que tenemos enunciados los diferentes pasos de las pruebas, necesitamos codificarlas para que estas se lleven a cabo. Para ello creamos el archivo “example.steps.js”, en la carpeta “/steps” con el siguiente código escrito en JavaScript ES6:

let {defineSupportCode} = require(&amp;amp;amp;amp;amp;#039;cucumber&amp;amp;amp;amp;amp;#039;);

let chai = require(&amp;amp;amp;amp;amp;#039;chai&amp;amp;amp;amp;amp;#039;).use(require(&amp;amp;amp;amp;amp;#039;chai-as-promised&amp;amp;amp;amp;amp;#039;));
let expect = chai.expect;

defineSupportCode( function({When, Then}) {
 When(&amp;amp;amp;amp;amp;#039;I navigate to {string}&amp;amp;amp;amp;amp;#039;, function(site) {
   return browser.get(site);
 });

 Then(&amp;amp;amp;amp;amp;#039;the title should be {string}&amp;amp;amp;amp;amp;#039;, function(title) {
   return expect(browser.getTitle()).to.eventually.eql(title);
 });

 When(&amp;amp;amp;amp;amp;#039;I click the Docs button&amp;amp;amp;amp;amp;#039;, function() {
   var docButton = element(by.css(&amp;amp;amp;amp;amp;#039;[title=&amp;amp;amp;amp;amp;amp;amp;quot;Docs&amp;amp;amp;amp;amp;amp;amp;quot;]&amp;amp;amp;amp;amp;#039;));

   return docButton.click();
 });

 Then(&amp;amp;amp;amp;amp;#039;I should see a {string} article&amp;amp;amp;amp;amp;#039;, function(title) {
   var article = element(by.id(&amp;amp;amp;amp;amp;#039;what-is-angular&amp;amp;amp;amp;amp;#039;));

   return expect(article.getText()).to.eventually.eql(title);
 });
});

A simple vista puede parecer difícil de entender, pero en realidad este código es muy sencillo.

Se puede observar como cada función viene precedida de una palabra e incluye un texto explicativo. Dicha palabra y texto deben ser iguales a uno de los pasos incluidos en las pruebas del archivo “.feature”, y es que, además, podemos recoger datos directamente de dicho texto gracias al uso de la directiva “{string}” y usarlos desde la variable que incluyamos en el código que implementa el paso de la prueba.

Dentro de cada función se irán recogiendo datos de la web a la que naveguemos a través de los elementos “browser”, “element” y “by”, donde:

  • browser es una instancia del navegador.
  • element es una instancia a un elemento del código HTML (árbol DOM del documento).
  • by es una instancia que nos permite buscar dicho elemento a través de diferentes características; como:
    • by.css: busca un elemento que incluya el código exacto a buscar.
    • by.id: busca un elemento por nombre de id.
    • by.className: busca un elemento por nombre de clase.
    • by.tagName: busca un elemento por nombre de etiqueta.

Si nos dirigimos al código HTML de la página web de Angular, podemos observar como el botón “Docs” contiene la propiedad “title=’Docs’”, de ahí que se puede buscar con el elemento “by.css”; o también podemos observar como el elemento del título del artículo “What is Angular?” incluye la propiedad “id=’what-is-angular’”, de ahí a que lo busquemos con el elemento “by.id”.


Con cada elemento se pueden realizar acciones como “click()” o “sendKeys()” por lo que, con todos estos pasos, lo que buscamos es emular las acciones manuales que un usuario realizaría en la página web, pero de manera automática.

Para confirmar el éxito de las pruebas, utilizamos el método “expect()” con el resultado que esperamos. Dicho método está proporcionado por Chai. En su documentación se puede ver la infinidad de posibilidades que nos permite comprobar.

Por último, para poder ejecutar estas pruebas, incluimos los siguientes «npm scripts» en el archivo package.json:

&amp;amp;amp;amp;amp;amp;amp;quot;pretest&amp;amp;amp;amp;amp;amp;amp;quot;: &amp;amp;amp;amp;amp;amp;amp;quot;webdriver-manager update&amp;amp;amp;amp;amp;amp;amp;quot;,
&amp;amp;amp;amp;amp;amp;amp;quot;test&amp;amp;amp;amp;amp;amp;amp;quot;: &amp;amp;amp;amp;amp;amp;amp;quot;protractor ./cucumber.conf.js&amp;amp;amp;amp;amp;amp;amp;quot;

Al ejecutar “npm run test”, veremos como se inicia una instancia de Selenium webdriver, de Chrome en este caso, que navegara a la página de Angular e irá realizando las pruebas emulando los pasos que hemos incluido en el archivo “example.steps.js”. Obviamente si la página web angular.io cambiara, los tests podrían dejar de funcionar.

El ejemplo de este artículo es bastante sencillo, pero, si se utilizan correctamente, Protactor y Cucumber son dos herramientas que nos permitirán realizar pruebas para todo tipo de aplicaciones web.

Os animo a probarlos por vuestra propia cuenta y, si tenéis alguna duda, ¡no dudéis en comentar!.

¡Un saludo!


Compartir en:

Relacionados