Facundo Gaumet // Joel A. Villarreal Bertoldi
Córdoba, 4 de Mayo de 2017
Supongamos que se nos presenta la siguiente situación:
Dos proyectos, uno con el 95% de cobertura con tests, otro con 45%. Pagan por error encontrado. ¿En cuál te gustaría trabajar?
Muchas herramientas miden la cobertura de sentencias, que también pueden conocerse como:
Muchas herramientas miden la cobertura de sentencias, que también pueden conocerse como:
COBERTURA DE SEGMENTOS
COBERTURA DE MÚLTIPLES CONDICIONES
COBERTURA DE RAMAS
var status = doSomething();
if (status === FATAL_ERROR) {
return 3;
}
// No errors, continue...
var status = doSomething();
if (status === FATAL_ERROR) {
return 3;
} else if (status === WARNING) {
// Recover from error.
}
// No errors, continue...
Podemos dividir el código testeado en tres categorías:
Podemos dividir el código testeado en tres categorías:
RIESGO ALTO
RIESGO MEDIO
RIESGO BAJO
class MyObject extends EventEmitter {
doSomething() {
// Alert we're going to something.
this.emit('beforeDoSomething');
// Effectively doing something.
this.x = this.x;
// Alert we've done something.
this.emit('afterDoSomething');
}
}
doSomething()
(call entry point)
event:beforeDoSomething
event:afterDoSomething
return;
this.x = this.x
¿Qué sucede en esta función?
describe('MyObject', function() {
before(function() {
this.obj = new MyObject();
});
it('should trigger all events',
function() {
this.obj.doSomething();
}
);
});
No sirve ya que no tiene expectativas.
describe('MyObject', function() {
before(function() {
this.obj = new MyObject();
});
it('should trigger all events',
function() {
const result = this.obj.doSomething();
expect(result).to.equal(true);
}
);
});
No sirve ya que doSomething() no tiene retorno.
Además, el retorno no tiene relación con los eventos.
VAMOS PASO A PASO
describe('MyObject', function() {
before(function() {
this.obj = new MyObject();
});
it(
'should trigger "before" event',
function() {
this.obj.on('beforeDoSomething', function() {
expect('everything').to.be.ok;
});
this.obj.doSomething();
});
});
Capturando un evento con listeners
it('should trigger "before" event',
function(done) {
myObject.on('beforeDoSomething',
function() {
done();
}
);
myObject.doSomething();
});
Capturando un evento con listeners: CALLBACKS
doSomething()
(call entry point)
event:beforeDoSomething
event:afterDoSomething
return;
this.x = this.x
Callback Testing
done()
it('should trigger all events in the cycle',
function(done) {
let calledBefore = false;
myObject.on('beforeDoSomething',
() => { calledBefore = true; });
myObject.on('afterDoSomething',
() => { if (calledBefore) { done(); } });
myObject.doSomething();
});
Patrón de múltiples eventos con un callback
doSomething()
(call entry point)
event:beforeDoSomething
event:afterDoSomething
return;
this.x = this.x
Callback Testing
calledBefore = true
calledBefore ? done() : Error
it('should trigger all events in the cycle',
function() {
const test = new Promise((resolve, reject) => {
let before = false;
myObject.on('beforeDoSomething',
() => { before = true });
myObject.on('afterDoSomething',
() => before ? resolve : reject);
});
return test()
.then(() => ...)
.catch(() => ...);
});
Captura de eventos + Promise Pattern
doSomething()
(call entry point)
event:beforeDoSomething
event:afterDoSomething
return;
this.x = this.x
Promise-Based Testing
before = true
before ? resolve() : reject()
Captura de eventos + Async/Await Pattern
!
IMPLEMENTACIÓN
NO ESTABLE
Captura de eventos + Async/Await Pattern
class MyAsyncObject {
getItem(id) {
return request(`/items/${id}`);
}
}
Captura de eventos + Async/Await Pattern
it('should return an item with
the given ID', async function() {
const item = await myObj.getItem(1);
expect(item.id).to.equal(1);
});
Es sencillo conseguir un 100% de cobertura, pero lo difícil es probarlo todo.
Las herramientas de cobertura son útiles, siempre y cuando las usemos para fomentar el pensamiento lógico, no reemplazarlo.