Testeando Javascript (1)

Introducción.

En esta serie de artículos nos proponemos tratar acerca del testing de aplicaciones desarrolladas con Javascript.

La elección de los temas viene marcada por situaciones prácticas que se nos han presentado en nuestro trabajo de desarrolladores web. Es decir, no pretendemos abarcar todos los aspectos de esta temática, ni tampoco abordaremos aspectos demasiado teóricos. Cuando creamos conveniente se harán referencias a recursos disponibles, en español u otros idiomas, que permitan profundizar aquellos apartados que nosotros tratemos superficialmente.

Considera estos artículos fundamentalmente como una iniciación o punto de partida. Sería importante, si quieres sacar el máximo provecho, que realices las prácticas aquí expuestas. Por supuesto, estamos abiertos a comentar lo que creas conveniente. Sin más preámbulos, manos a la obra. Nuestro primer artículo tratará de Express.

Testeando una aplicación Express.

Probaremos una sencilla aplicación Express que corre en un servidor Node. Comprobaremos que las respuestas proporcionadas se corresponden con valores esperados y deseados.

El plan.

Crearemos un proyecto desde cero. Las tareas que llevaremos a cabo se pueden dividir en los siguientes apartados:
1. Poner en marcha nuestra aplicación:
* crear la estructura de carpetas y archivos del proyecto.
* instalar express.
* nuestra aplicación será codificada en ES6 y por lo tanto necesitaremos babel.
* una buena práctica es codificar de acuerdo a standards seguidos por la mayoría de los programadores avanzados y por lo tanto necesitaremos eslint.
2. Utilizar las herramientas de test:
* instalar Mocha
* instalar Chai
* instalar request
* codificar nuestros tests.

Poner en marcha nuestra aplicación.

Se espera que tengas instalado en tu plataforma Node y npm a ser posible que estén actualizados. Yo utilizo Linux Mint pero supongo que los comandos valdrán igualmente en tu OS. En tu carpeta de proyectos crea una carpeta, p.ej., testing y sitúate en ella para ejecutar los comandos siguientes:

$ mkdir src test dist
$ touch src/server.js test/server.js
$ touch .babelrc .eslintrc
$ tree -a
.
├── .babelrc
├── dist
├── .eslintrc
├── src
│   └── server.js
└── test
└── server.js

3 directories, 4 files

El código puede variar en tu OS. A partir de ahora, los comandos funcionarán cualquiera que sea éste.

Inciamos npm:

$ npm init -y
Wrote to /home/antonio/Proyectos/pruebas/testing/package.json:

{
"name": "testing",
"version": "1.0.0",
"description": "",
"main": "index.js",
"directories": {
"test": "test"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}

Completa o cambia los datos si así lo deseas. Empezaremos a instalar los packages que necesitaremos. Primero, las devDependencies

$ npm i babel babel-cli babel-preset-es2015 eslint babel-eslint --save-dev

Escribiremos esto en .babelrc:

{
"presets": ["es2015"]
}

y esto en .eslintrc:

{
"parser": "babel-eslint",
"env": {
"node": true,
"mocha": true
},
"rules": {
"object-curly-spacing": 1,
"no-undef": 1
}
}

A continuación instalamos express:

$ npm install express --save

Finalizadas, de momento, las instalaciones empezaremos con el código propiamente dicho. Editamos el archivo src/server.js

/**
* src/server.js
*/

const express = require("express");
const app = express();

app.get("/", (req, res) => {
const text = 'welcome to my homesite';

res.send(text);
});

app.listen(3000);

Una aplicación muy sencilla pero válida para nuestros propósitos. Añadiremos la siguiente línea a la sección de script del package.json:

"start": "./node_modules/.bin/babel-node ./src/server.js",

y ejecutamos:

$ npm start

> testing@1.0.0 start /home/antonio/Proyectos/pruebas/testing
> babel-node ./src/server.js

que pondrá en marcha nuestro servidor. Si abrimos un navegador por http://localhost:3000 veremos el sencillo mensaje de bienvenida. Es importante tener en cuenta que la ejecución del comando continúa mientras no lo ‘matemos’. En linux haremos CTRL+c para ese propósito.

Hasta ahora, poco nuevo para muchos de nosotros. Pero nos hemos acercado mucho a nuestro objetivo real. De hecho, ya podemos empezar a testear dado que ya tenemos algo que testear.

Utilizar las herramientas de test.

Volvemos al estado instalador. Ejecutemos:

$ npm install mocha chai --save-dev
... ... ...
$ npm install request --save

Las dos primeras son propiamente nuestras herramientas de test y la tercera nos permitirá realizar solicitudes a nuestro servidor y capturar su respuesta.

“* Mocha is a simple, flexible, fun JavaScript test framework for node.js and the browser*”. Esta es la manera en la que el equipo de desarrolladores de Mocha lo describen. De este framework utilizaremos tres herramientas:
1. su binario nos permitirá lanzar la ejecución de los test que tengamos preparados.
2. la función describe
3. la función it

Escribamos la siguiente línea en sustitución de la línea “test” en el apartado de scripts de nuestro package.json:

"test": "./node_modules/.bin/mocha –reporter spec || true"

y ejecutemos npm test obtendremos la siguiente salida:

$ npm test

> testing@1.0.0 test /home/antonio/Proyectos/pruebas/testing
> mocha --reporter spec || true

0 passing (3ms)

Es decir Mocha ejecutará nuestros tests. En este caso, aun no hay test que realizar. Una cosa a destacar es que no hace falta indicarle en qué carpeta va a encontrar los test a realizar. De hecho, ejecutará todos los tests que encuentre en la carpeta test.
Bien escribamos nuestro primer test. Éste hará una solicitud a nuestro servidor y comprobará que la respuesta es el mensaje de bienvenida que ya conocimos anteriormente. Para ello editemos el archivo test/server.js

const expect = require("chai").expect
const request = require('request')

describe("Testeando un Node server =>", () => {

describe("Está en funcionamiento? =>", () => {

let url = "http://localhost:3000";

it("Si está funcionando el status de la respuesta deberia ser 200", (done) => {
request(url, (error, response, body) => {
expect(response.statusCode).to.equal(200)
done()
})
})
})
})

Si ejecutamos ahora npm test nos dará esta salida:

$ npm test

> testing@1.0.0 test /home/antonio/Proyectos/pruebas/testing
> mocha --reporter spec || true

Testeando Node server =>
Está en funcionamiento? =>
1) Si está funcionando el status de la respuesta deberia ser 200

0 passing (37ms)
1 failing

1) Testeando Node server => Está en funcionamiento? => Si está funcionando el status de la respuesta deberia ser 200:
Uncaught TypeError: Cannot read property 'statusCode' of undefined
at Request.request [as _callback] (test/server.js:12:24)
at self.callback (node_modules/request/request.js:187:22)
at Request.onRequestError (node_modules/request/request.js:813:8)
at Socket.socketErrorListener (_http_client.js:308:9)
at emitErrorNT (net.js:1272:8)
at _combinedTickCallback (internal/process/next_tick.js:74:11)
at process._tickCallback (internal/process/next_tick.js:98:9)

El test ha fallado porque no se puede leer la propiedad status code de la respuesta. Efectivamente, no habíamos arrancado el servidor. Abramos una nueva consola y ejecutemos npm start y npm testsucesivamente. La salida ahora sería:

$ npm test

> testing@1.0.0 test /home/antonio/Proyectos/pruebas/testing
> mocha --reporter spec || true

Testeando Node server =>
Está en funcionamiento? =>
✓ Si está funcionando el status de la respuesta deberia ser 200 (56ms)

1 passing (67ms)

Enhorabuena, has ejecutado tu primer test OK. Vale hay respuesta, pero ¿es la esperada? Añadimos lo siguiente a continuación de la función it anterior en test/server.js

it("Debería haber un determinado mensaje de bienvenida", (done) => {
request(url, (error, response, body) => {
expect(body).to.equal("welcome to my homesite")
done()
})
})

y ejecutemos de nuevo el test. Esta es la salida ahora:

$ npm test

> testing@1.0.0 test /home/antonio/Proyectos/pruebas/testing
> mocha --reporter spec || true

Testeando Node server =>
Está en funcionamiento? =>
✓ Si está funcionando el status de la respuesta deberia ser 200 (82ms)
✓ Debería haber un determinado mensaje de bienvenida

2 passing (103ms)

Vaya dos test OK de dos posibles. La cosa marcha. Evidentemente, si el body de la response fuera otro (‘welcome, guest’, p.ej.) el segundo test fallaría. También fallaría si hubieramos escrito:

expect(body).to.equal("welcome, guest");

en el test. Bien, ¿no?
Nuestro servidor es muy simple. De hecho solo puede mostrar una página. Si cambiamos la url de nuestro test a http://localhost:3000/books ,p.ej., los dos test fallan porque la respuesta tiene un tatusCode de 404, y el body de la respuesta sería Cannot GET /books. Os animamos a que intentéis modificar src/test.js para comprobar esta afirmación.

Como se puede observar, por cada página (más bien, url) de nuestra web podríamos tener su correspondiente test que comprobara que funciona de acuerdo a lo esperado. Cosa que haremos en un nuevo artículo porque éste se nos ha ido un poco de las manos. Ese nuevo artículo no tendrá tanta tarea previa e irá directamente al grano. O al menos eso esperamos.

Esperamos que os halla sido de utilidad. Cualquier comentario es bienvenido. Gracias por la atención prestada. Hasta la próxima.