node.js - test - pruebas unitarias node js
¿Cómo pruebo adecuadamente las promesas con mocha y chai? (4)
La siguiente prueba se comporta de manera extraña:
it(''Should return the exchange rates for btc_ltc'', function(done) {
var pair = ''btc_ltc'';
shapeshift.getRate(pair)
.then(function(data){
expect(data.pair).to.equal(pair);
expect(data.rate).to.have.length(400);
done();
})
.catch(function(err){
//this should really be `.catch` for a failed request, but
//instead it looks like chai is picking this up when a test fails
done(err);
})
});
¿Cómo debo manejar adecuadamente una promesa rechazada (y probarla)?
¿Cómo debo manejar adecuadamente una prueba fallida (es decir:
expect(data.rate).to.have.length(400);
Aquí está la implementación que estoy probando:
var requestp = require(''request-promise'');
var shapeshift = module.exports = {};
var url = ''http://shapeshift.io'';
shapeshift.getRate = function(pair){
return requestp({
url: url + ''/rate/'' + pair,
json: true
});
};
Aquí está mi opinión:
-
usando
async/await
- no necesita módulos chai adicionales
- evitando el problema de captura, @TheCrazyProgrammer señaló anteriormente
Una función de promesa retrasada, que falla, si se le da un retraso de 0:
const timeoutPromise = (time) => {
return new Promise((resolve, reject) => {
if (time === 0)
reject({ ''message'': ''invalid time 0'' })
setTimeout(() => resolve(''done'', time))
})
}
// ↓ ↓ ↓
it(''promise selftest'', async () => {
// positive test
let r = await timeoutPromise(500)
assert.equal(r, ''done'')
// negative test
try {
await timeoutPromise(0)
// a failing assert here is a bad idea, since it would lead into the catch clause…
} catch (err) {
// optional, check for specific error (or error.type, error. message to contain …)
assert.deepEqual(err, { ''message'': ''invalid time 0'' })
return // this is important
}
assert.isOk(false, ''timeOut must throw'')
log(''last'')
})
La prueba positiva
es bastante simple.
La falla inesperada (simulación por
500→0
) fallará la prueba automáticamente, ya que la promesa rechazada aumenta.
La prueba negativa usa la idea try-catch-idea. Sin embargo: ''quejarse'' sobre un pase no deseado ocurre solo después de la cláusula catch (de esa manera, no termina en la cláusula catch (), lo que desencadena más errores pero engañosos.
Para que esta estrategia funcione, uno debe devolver la prueba de la cláusula catch. Si no desea probar nada más, use otro bloque it ().
Como ya se señaló
here
, las versiones más nuevas de Mocha ya son compatibles con Promise.
Pero dado que el OP preguntó específicamente sobre Chai, es justo señalar el paquete
chai-as-promised
que proporciona una sintaxis limpia para probar las promesas:
usando chai-como-prometió
A continuación, le mostramos cómo puede usar chai-as-prometido para probar los casos de
resolve
y
reject
de una promesa:
var chai = require(''chai'');
var expect = chai.expect;
var chaiAsPromised = require("chai-as-promised");
chai.use(chaiAsPromised);
...
it(''resolves as promised'', function() {
return expect(Promise.resolve(''woof'')).to.eventually.equal(''woof'');
});
it(''rejects as promised'', function() {
return expect(Promise.reject(''caw'')).to.be.rejectedWith(''caw'');
});
sin chai según lo prometido
Para dejar en claro lo que se está probando, aquí está el mismo ejemplo codificado sin chai-como-prometió:
it(''resolves as promised'', function() {
return Promise.resolve("woof")
.then(function(m) { expect(m).to.equal(''woof''); })
.catch(function(m) { throw new Error(''was not supposed to fail''); })
;
});
it(''rejects as promised'', function() {
return Promise.reject("caw")
.then(function(m) { throw new Error(''was not supposed to succeed''); })
.catch(function(m) { expect(m).to.equal(''caw''); })
;
});
Hay una mejor solución. Simplemente devuelva el error con hecho en un bloque catch.
// ...
it(''fail'', (done) => {
// any async call that will return a Promise
ajaxJson({})
.then((req) => {
expect(1).to.equal(11); //this will throw a error
done(); //this will resove the test if there is no error
}).catch((e) => {
done(e); //this will catch the thrown error
});
});
esta prueba fallará con el siguiente mensaje:
AssertionError: expected 1 to equal 11
Lo más fácil sería utilizar el soporte de promesas incorporado que Mocha tiene en las versiones recientes:
it(''Should return the exchange rates for btc_ltc'', function() { // no done
var pair = ''btc_ltc'';
// note the return
return shapeshift.getRate(pair).then(function(data){
expect(data.pair).to.equal(pair);
expect(data.rate).to.have.length(400);
});// no catch, it''ll figure it out since the promise is rejected
});
O con Nodo moderno y asíncrono / espera:
it(''Should return the exchange rates for btc_ltc'', async () => { // no done
const pair = ''btc_ltc'';
const data = await shapeshift.getRate(pair);
expect(data.pair).to.equal(pair);
expect(data.rate).to.have.length(400);
});
Dado que este enfoque es una promesa de principio a fin, es más fácil de probar y no tendrá que pensar en los casos extraños en los que está pensando, como las llamadas impares de
done()
todas partes.
Esta es una ventaja que Mocha tiene sobre otras bibliotecas como Jasmine en este momento.
También es posible que desee verificar
Chai As Promised, lo
que lo haría aún más fácil (no
.then
), pero personalmente prefiero la claridad y simplicidad de la versión actual