Curso de




Día 4: Pruebas asíncronas

Vuestro anfitrión


(según mi hija de 5 años)

Ingeniero senior en MediaSmart Mobile
Co-organizador de Node.js Madrid
@pinchito

Guión


  • Pruebas asíncronas
  • Sesión práctica: prueba asíncrona
  • Control
  • Sesión práctica: prueba de sockets

Pruebas Asíncronas


¿Quién automatiza al automatizador?

Anónimo

Tipos de pruebas


Pruebas unitarias


Pruebas de integración /  de sistemas


Pruebas de carga



Pruebas automáticas: ¡las mejores!

Pruebas de código asíncrono


No basta con correr el código y ver el resultado


Requieren una librería especial


Veremos cómo usar testing

Librería especializada

Otras librerías


Mocha


Vows


nodeunit


jasmine

Éxito y fracaso


testing.failure(
        "Failed to do something", 
        callback); 
    

Da la prueba por fallida con un mensaje


testing.success(
        "Well done!", 
        callback); 
    

Da la prueba por buena con un mensaje

Aserciones


Para comprobar que un valor contiene lo que se espera


testing.assert(value, "Error in value", callback); 

La variable value debe ser cierta (true o un objeto)


testing.assertEquals(sum(2, 2), 4, "Wrong sum", callback); 
La función sum(2,2) debe devolver 4

Ejecución asíncrona


testing.check(error, "There is an error", callback); 
Comprueba que no haya error; si lo hay, falla el test

testing sigue la convención habitual de node para callbacks:

doSomethingAsync(function(error, result) {
if (error) {
console.error('Could not do something: ' + error);
return;
}
});

El error contiene algo sólo si la función falló


Sesión Práctica 1: prueba asíncrona


Comprobar que la función returnFiveAsync() no da error

y devuelve el valor 5


código a probar

Función que envía 5 a la callback

inmediatamente pero asíncrono

function returnFiveAsync(callback) {
    setImmediate(function() {
        callback(null, 5);
});
}


setImmediate(callback, args...): llama a la callback

después de los eventos de I/O

y antes de setTimeout() y setInterval()

Fuente: setImmediate()

Solución


function testAsync(callback) {
returnFiveAsync(function(error, result) {
testing.check(error, 'Could not return five', callback);
testing.assertEquals(result, 5, 'Invalid result', callback);
testing.success(callback);
});
}
Casi todas las llamadas de testing terminan en una callback

¡Bien!

Control


testing.run([testFirst, testSecond], timeout, callback); 

Corre las pruebas testFirst() y testSecond()

testing.show(results); 

Muestra el resultado de las pruebas


Uso habitual:

// run tests if invoked directly
if (__filename == process.argv[1])
{
testing.run([testFirst, testSecond], testing.show);
}

¡Automatiza!


Diseña un API de control

Arranca y para el sistema usando el API


Tests auto-contenidos: limpia al terminar


Tres reglas básicas:

  • Un único botón
  • Haz los fallos visibles
  • Sin intervención humana

Sesión práctica 3: pruebas


Diseñar las pruebas para el servidor de sockets

usando testing


Crear un API de control


Añadir a test.js

Diseño de la prueba


Arrancar el servidor de sockets en un puerto diferente (1705)


Conectar con un socket y enviar "hello"


Verificar que devuelve "world"


Cerrar el socket


Parar el servidor

API de control

Encapsular el arranque del servidor en una función

function start(port, callback) {
    var server = net.createServer(function(connection) {
        console.log('Conexión abierta');
        ...
    });
    server.listen(port, callback);
    return server;
}

Añadir la parada del servidor: server.close()

Llamar en secuencia:

function testServer(callback) {
var server = start(1705, function(error, result) {
server.stop(function(error, result) {
....
});
});
}

Prueba completa


function testServer(callback) {
var port = 1705;
var server = start(port, function(error) {
testing.check(error, 'Could not start server', callback);
console.log('started');
var socket = net.connect(port, 'localhost', function(error) {
testing.check(error, 'Could not connect', callback);
socket.on('data', function(data) {
console.log('Received ' + data);
var message = String(data).trim();
if (message == 'Hello?')
{
socket.write('hello');
return;
}
testing.assertEquals(message, 'world', 'Bad response', callback);
server.close(function(error) {
testing.check(error, 'Could not stop server', callback);
testing.success(callback);
});
});
});
});
}

Ejercicios


Eliminar todos los console.log()


Añadir otra prueba testError():

envía otra cadena, comprueba que obtiene 'ERROR'


Añadir una prueba que arranque dos servidores

en puertos distintos y los pare

¡Tachán!



Thanks!





Curso de Node.js Amaris: Pruebas asíncronas

By Alex Fernández

Curso de Node.js Amaris: Pruebas asíncronas

Curso para Amaris de Node.js, 2014-11-06: pruebas asíncronas

  • 2,434