Buscar..
Afirmacion basica
En su nivel más básico, Unit Testing en cualquier idioma proporciona afirmaciones contra algunos resultados conocidos o esperados.
function assert( outcome, description ) {
var passFail = outcome ? 'pass' : 'fail';
console.log(passFail, ': ', description);
return outcome;
};
El popular método de afirmación anterior nos muestra una manera rápida y fácil de afirmar un valor en la mayoría de los navegadores web e intérpretes como Node.js con prácticamente cualquier versión de ECMAScript.
Una buena prueba de unidad está diseñada para probar una unidad de código discreta; Por lo general una función.
function add(num1, num2) {
return num1 + num2;
}
var result = add(5, 20);
assert( result == 24, 'add(5, 20) should return 25...');
En el ejemplo anterior, el valor de retorno de la función add(x, y)
o 5 + 20
es claramente 25
, por lo que nuestra afirmación de 24
debería fallar, y el método de afirmación registrará una línea de "falla".
Si simplemente modificamos el resultado esperado de la aserción, la prueba tendrá éxito y la salida resultante tendrá un aspecto similar a este.
assert( result == 25, 'add(5, 20) should return 25...');
console output:
> pass: should return 25...
Esta simple afirmación puede asegurar que en muchos casos diferentes, su función "agregar" siempre devolverá el resultado esperado y no requiere marcos o bibliotecas adicionales para funcionar.
Un conjunto de aserciones más riguroso se vería así (usando var result = add(x,y)
para cada aserción):
assert( result == 0, 'add(0, 0) should return 0...');
assert( result == -1, 'add(0, -1) should return -1...');
assert( result == 1, 'add(0, 1) should return 1...');
Y la salida de la consola sería esta:
> pass: should return 0...
> pass: should return -1...
> pass: should return 1...
Ahora podemos decir con seguridad que add(x,y)
... debe devolver la suma de dos enteros . Podemos resumirlos en algo como esto:
function test__addsIntegers() {
// expect a number of passed assertions
var passed = 3;
// number of assertions to be reduced and added as Booleans
var assertions = [
assert( add(0, 0) == 0, 'add(0, 0) should return 0...'),
assert( add(0, -1) == -1, 'add(0, -1) should return -1...'),
assert( add(0, 1) == 1, 'add(0, 1) should return 1...')
].reduce(function(previousValue, currentValue){
return previousValue + current;
});
if (assertions === passed) {
console.log("add(x,y)... did return the sum of two integers");
return true;
} else {
console.log("add(x,y)... does not reliably return the sum of two integers");
return false;
}
}
Pruebas de unidad prometen con Mocha, Sinon, Chai y Proxyquire
Aquí tenemos una clase simple para probar que devuelve una Promise
basada en los resultados de un procesador de ResponseProcessor
externo que demora en ejecutarse.
Para simplificar, asumiremos que el método processResponse
nunca fallará.
import {processResponse} from '../utils/response_processor';
const ping = () => {
return new Promise((resolve, _reject) => {
const response = processResponse(data);
resolve(response);
});
}
module.exports = ping;
Para probar esto podemos aprovechar las siguientes herramientas.
Uso el siguiente script de test
en mi archivo package.json
.
"test": "NODE_ENV=test mocha --compilers js:babel-core/register --require ./test/unit/test_helper.js --recursive test/**/*_spec.js"
Esto me permite usar la sintaxis de es6
. Hace referencia a un test_helper
que se verá como
import chai from 'chai';
import sinon from 'sinon';
import sinonChai from 'sinon-chai';
import chaiAsPromised from 'chai-as-promised';
import sinonStubPromise from 'sinon-stub-promise';
chai.use(sinonChai);
chai.use(chaiAsPromised);
sinonStubPromise(sinon);
Proxyquire
nos permite inyectar nuestro propio código auxiliar en lugar del ResponseProcessor
externo. Entonces podemos usar sinon
para espiar los métodos de ese talón. Usamos las extensiones para chai
que chai-as-promised
inyecta para verificar que la promesa del método ping()
está fullfilled
, y que eventually
devuelve la respuesta requerida.
import {expect} from 'chai';
import sinon from 'sinon';
import proxyquire from 'proxyquire';
let formattingStub = {
wrapResponse: () => {}
}
let ping = proxyquire('../../../src/api/ping', {
'../utils/formatting': formattingStub
});
describe('ping', () => {
let wrapResponseSpy, pingResult;
const response = 'some response';
beforeEach(() => {
wrapResponseSpy = sinon.stub(formattingStub, 'wrapResponse').returns(response);
pingResult = ping();
})
afterEach(() => {
formattingStub.wrapResponse.restore();
})
it('returns a fullfilled promise', () => {
expect(pingResult).to.be.fulfilled;
})
it('eventually returns the correct response', () => {
expect(pingResult).to.eventually.equal(response);
})
});
Ahora, en cambio, supongamos que desea probar algo que utiliza la respuesta de ping
.
import {ping} from './ping';
const pingWrapper = () => {
ping.then((response) => {
// do something with the response
});
}
module.exports = pingWrapper;
Para probar el pingWrapper
aprovechamos
Como antes, Proxyquire
nos permite inyectar nuestro propio código auxiliar en lugar de la dependencia externa, en este caso, el método ping
que probamos anteriormente. Luego podemos usar sinon
para espiar los métodos de ese código auxiliar y aprovechar la sinon-stub-promise
para permitirnos returnsPromise
. Esta promesa puede ser resuelta o rechazada como deseamos en la prueba, para probar la respuesta del contenedor a eso.
import {expect} from 'chai';
import sinon from 'sinon';
import proxyquire from 'proxyquire';
let pingStub = {
ping: () => {}
};
let pingWrapper = proxyquire('../src/pingWrapper', {
'./ping': pingStub
});
describe('pingWrapper', () => {
let pingSpy;
const response = 'some response';
beforeEach(() => {
pingSpy = sinon.stub(pingStub, 'ping').returnsPromise();
pingSpy.resolves(response);
pingWrapper();
});
afterEach(() => {
pingStub.wrapResponse.restore();
});
it('wraps the ping', () => {
expect(pingSpy).to.have.been.calledWith(response);
});
});