Los tests de aceptación o "end-to-end" son solo la punta del diseño guiado por pruebas, pero adquieren una importancia muy grande en aplicaciones "legacy".

Este tipo de tests prueban "casi" como si fuéramos nosotros los que estamos interactuando como "personas" o "actores" con nuestro software.

Estamos de acuerdo con que son las pruebas unitarias y de integración (en menor medida) las que deben ocupar nuestro tiempo, esfuerzo y cariño.

Pero, ¿qué ocurre cuando nuestra aplicación nunca ha estado sometida a tests automatizados?

De ningún tipo. Solo hemos hecho pruebas manuales. Cada vez que lanzamos un cambio de versión repetimos una serie de procesos "a manita" para ver si todo esta correcto y nada se rompe.

Estarás de acuerdo conmigo en que las cosas se complican mucho si esa aplicación que queremos mejorar es de alto valor para el negocio.

Así que empecemos por algún sitio.

Lo contamos ya con detalle en el episodio 18 y 19 de Web Reactiva Premium. Suscríbete para disfrutar de todo ese contenido.

Codeception al rescate

Codeception es una librería de testing (de todos los niveles, no solo aceptación) con mucha veteranía y basada en PHP.

Tiene una versión para JavaScript llamada CodeceptJS.

Nos centraremos en generar nuestros tests desde un proyecto que solo hará eso: lanzar las pruebas E2E (end-to-end) desde allí hacia nuestro servidor local o de staging.

Instalando Codeception

Seguimos los pasos descritos en su documentación. Instalamos con composer:

composer require "codeception/codeception" --dev

Mi recomendación es no instalarlo de forma global, salvo que ya tengas claro que quieres levantar testings en muchos sitios.

Generamos toda la base de carpetas y código:

./vendor/bin/codecept bootstrap

Y por último crearemos el primer test:

./vendor/bin/codecept generate:cest acceptance First

Detalles de configuración

Lo tenemos todo listo y en la carpeta tests/acceptance/FirstCest.php tendremos alojado el escenario con el que vamos a empezar a jugar.

Antes de esto hay que realizar una pequeña modificación en la configuración específica de las pruebas de aceptación.

En tests/acceptance.suite.yml tendremos esto:

actor: AcceptanceTester
modules:
    enabled:
        - PhpBrowser:
            url: https://pastebin.com
        - \Helper\Acceptance
    step_decorators: ~      

Codeception tiene mucha cuerda, así que no vamos a ver en detalle todo. Sólo queremos saber las bases del funcionamiento.

Si te puedes fijar en que la URL de las pruebas va a ser pastebin.com . El popular sitio donde pegar texto para que otros lo vean será nuestra "víctima".

Tipos de tests de aceptación

Antes de continuar te cuento algo bastante importante. En Codeception hay dos tipos de tests de Aceptación.

  • Los basados en PHPBrowser. No abrimos el navegador sino que lo simulamos con la librería SymfonyBrowserKit . Esto quiere decir que no tendremos la opción de ejecutar la web con JavaScript.
  • Los basados en WebDriver. Aquí si arrancamos un browser para ejecutar las pruebas. TIene compatibilidad con Selenium y PhantomJS. No es difícil encontrar soluciones también para puppeteer.

Nos quedamos con el primero. Son más rápidas de ejecutar y todo lo que aprendamos en ellas nos servirán para las que si abren un Firefox o un Chrome.

Si te advierto que Codeception tiene una forma peculiar de hacer algunas cosas, con lo que aprovecha este desembarco iniciático para comprobar si te interesa incluirlo en el stack tecnológico de tus aplicaciones o mantenerlo de forma externa.

Para tu tranquilidad si te digo que se basa en el standard de facto: PHPUnit.

Primer tests de aceptación

En nuestra clase de pruebas dejamos este código:

<?php 
//tests/acceptance/FirstCest.php
  
class FirstCest
{
    public function sendNewPastebin(AcceptanceTester $I)
    {
        $I->amOnPage('/');
        $I->see('New Paste');
    }
}

Ejecutamos el test:

./vendor/bin/codecept run acceptance FirstCest --steps

Nota: Las combinaciones para filtrar los tests en la línea de comandos son muy amplias. Si quieres echar un vistazo a todas sus opciones la documentación en línea es muy completa.

El resultado debería ser este:

Primer test con Codeception

Nuestro script ha emulado la carga de la página principal de pastebin y ha buscado que exista en algún sitio las palabras "New Paste".

Ese método see tiene muchísimas variantes, no dejes de buscar la más adecuada.

Usemos el formulario de creación de nuevos contenidos, que para eso estamos aquí.

<?php 
  
class FirstCest
{
    public function sendNewPastebin(AcceptanceTester $I)
    {
        $I->amOnPage('/');
        $I->see('New Paste');
        $I->fillField('paste_code', 'Prueba de Acceptance Testing');
        $I->click('#submit');
    }
}

Con fillField rellenamos el campo textarea con el atributo paste_code (Codeception buscará el que mejor encaje, sino lo encuentra, protestará).

Escribimos un texto y terminamos pulsando el botón de publicar. En este caso, para que veas la polivalencia de Codeception, localizamos ese submit por su atributo identificador id.

Después del envío de formulario

Completemos el proceso comprobando que todo ha sido correcto:

<?php 
  
class FirstCest
{
    public function sendNewPastebin(AcceptanceTester $I)
    {
        $I->amOnPage('/');
        $I->see('New Paste');
        $I->fillField('paste_code', 'Prueba de Acceptance Testing');
        $I->click('#submit');
        $I->seeInField('paste_code', 'Prueba de Acceptance Testing');
    }
}

Tras hacer 'click' el tests esperará, sin que nosotros se lo tengamos que decir, a que cargue la siguiente página. Si estuviéramos en el otro tipo de test, el WebDriver si podríamos establecer una espera. En PhpBrowser nuestra prueba lee directamente del HTML.

Así que ahí solo tenemos que ver si en el campo paste_code está escrito ese texto.

(Nota: No te lo he dicho antes, pero te recomiendo vivamente hacer este proceso manualmente tu por tu cuenta, para ver lo que se cuece antes de probarlo).

Capturas de pantalla en formato HTML

Para que termines de creerte lo que hace todo esto, añadamos un paso más a la prueba:

<?php 
  
class FirstCest
{
    public function sendNewPastebin(AcceptanceTester $I)
    {
        $I->amOnPage('/');
        $I->see('New Paste');
        $I->fillField('paste_code', 'Prueba de Acceptance Testing');
        $I->click('#submit');
        $I->makeHtmlSnapshot();
        $I->seeInField('paste_code', 'Prueba de Acceptance Testing');
    }
}

Este nuevo método hará una captura en ese punto del HTML que está viendo el test al ejecutarse. Y la guardará en la carpeta tests\_ouput\_debug.

Justo en la carpeta donde Codeception guarda los resultados también te encontrarás el HTML de la página que da fallo en el test (si así fuera). Te informa en consola, así que es imposible perderse.

Capturando datos y añadiendo aserciones

Queremos capturar también datos de las páginas que cargamos. Esta página genera una nueva URL para cada publicación, así que nos interesa capturarla. Ahora lo añadimos al final del código con el método grabFromCurrentUrl() y lo exponemos a la consola con expectTo.

Puede también que a estas alturas ya hayas tenido problemas con el detector de "gente mala" de pastebin. Tiene un férreo control de spam así que vamos a introducir una aserción más en el código para que nos devuelva un error si la página nos bloquea.

<?php 

class FirstCest
{
    public function sendNewPastebin(AcceptanceTester $I)
    {
        $I->amOnPage('/');
        $I->see('New Paste');
        $I->fillField('paste_code', 'Prueba de Acceptance Testing');
        $I->click('#submit');
        $I->makeHtmlSnapshot();
        $I->dontSeeInTitle('Possible Spam Detected');
        $I->seeInField('paste_code', 'Prueba de Acceptance Testing');
        $uri = $I->grabFromCurrentUrl();
        $I->expectTo("El alias de URL es ${uri}");

    }
}

En efecto dontSeeInTitle va a comprobar que en la etiqueta <title> no se contenga ese texto. Si nos apareciera la página de control de "persona humana" tendríamos un error.

Aquí tendríamos el resultado final:

Acabamos el primer test con Codeception

Conclusión

El testing es algo que tendemos a evitar hacer, y, ahí, nos equivocamos. En la sesión en directo que dedicamos a las pruebas unitarias la pregunta más recurrente de los asistentes fue precisamente: "¿Y esto como lo uso en un proyecto real?".

Allí y aquí tenemos la primera piedra del camino.

Suscríbete a la Zona Premium para seguir caminando por ese sendero con toda la comunidad que está allí dentro.

Si te interesa este tema y quieres saber más, no dejes de contactar conmigo.

¿Quieres ser mejor desarrollador?

Escrito por Dani

Soy programador web freelance. Especialista en frameworks basados en PHP como Drupal, aunque también me gusta trabajar con microframeworks en varios lenguajes y, por supuesto, tengo a Javascript de gran aliado. aquí.
comments powered by Disqus