Sinon
teisiti (fr)
Kuidas testida, et funtsioon välja kutsumist? Funktsioon tuleb välja kutsuda isoleeritult, et testida just kindlat funtsionaalsust.
Võtame aluskes järgneva objekti, mille dropClass funtsiooni välja kutsume:
student = {
dropClass: function(classId, cb) {
//do stuff
cb();
}
};
Võib kirjutada funtsiooni, mis jäljendab tegelikku funtsiooni ja muuta seal jälgimisparameetrit:
describe('testing function calls', () => {
it("should call the callback", () => {
let called = false;
function callback() {
called = true;
}
student.dropClass(1, callback);
called.should.be.true;
});
});
Kuid see nõuab palju käsitööd ja saame hoopis kasutada funtsioonide jälgimiseks loodud eraldi raamistikku – sinon.
npm install sinon
const sinon = require('sinon');
Sinon on JavaScripti raamistik, mis testib funktsioonide välja kutsumist ja võimaldab kirjutada pettefunktsioone.
Spy
nuhk, spioon
Spy on funktsioon, mida sinon jälgib, ja oskab välja tuua: kas ja kui mitu korda on spy funtsiooni välja kutsutud ning mis parameetrid talle iga kord kaasa anti.
describe("student.dropClass", function() {
it("should call the callback", () => {
const spy = sinon.spy();
student.dropClass(1, spy);
spy.called.should.be.true;
});
});
Spy võib jälgida ka teatud kindla funtsiooni välja kutsumist, kui anname sisendina kaasa funktsiooni, mida tahame jälgida:
it("should call the callback and log to the console", () => {
function onClassDropped() {
console.log("onClassDropped was called");
}
var spy = sinon.spy(onClassDropped);
student.dropClass(1, spy);
spy.called.should.be.true;
});
Stub
tükk, konts, nukk; välja juurima
Stub võimaldab jälgida tervet objekti. Kuna me tavaliselt töötame objektidega, mitte tavaliste funktsioonidega, siis stub-ide kasutamine on testimise käigus enam levinud.
describe.only("stubs", () => {
const student = {
dropClass: function(classId, cb) {
//do stuff
if (!!cb.dropClass) {
cb.dropClass();
} else {
cb();
}
}
};
const schedule = {
dropClass: function() {
console.log("class dropped");
}
};
it("should call a stubbed method", () => {...});
});
});
Stub võimaldab testida objekti meetodite väljakutsumist:
it("shoud call a stubbed method", () => {
const stub = sinon.stub(schedule);
student.dropClass(1, stub.dropClass);
stub.dropClass.called.should.be.true;
});
Viimase lahenduse oleks saanud lihtsalt ka spy-funktsiooniga lahendada. Kuid stubidel on palju lisavõimalusi – üks neist võimalustest on see, et me saame kontrollida, kuidas nad funktsioneerivad (muuta väärtust vastavalt oma vajadustele).
Näiteks testime lihtsat funktsiooni, mis tagastab alati tõese väärtuse:
const student = {
addClass: function(schedule) {
if(!schedule.classIsFull()) {
return true;
} else {
return false;
}
}
};
const schedule = {
classIsFull: function() {
return true;
}
};
Funtsiooni väärtusega saame mängida.
it("should return true when the class is not full", () => {
const returnVal = student.addClass(schedule);
returnVal.should.be.true;
});
Kuna praegu tagastab schedule.classIsFull() meetod alati tõese väärtuse, siis test ebaõnnestub, kuid stub võimaldab testis objekti meetodi tulemit muuta ka kasutada seda erinevate võimaluste läbi testimiseks:
it("should return true when the class is not full", () => {
const stub = sinon.stub(schedule);
stub.classIsFull.returns(false);
const returnVal = student.addClass(stub);
returnVal.should.be.true;
});
Stub-isid saab kontrollida palju paremini, kui spy-sid ja selle tõttu kasutatakse neid sagedamini.
Mock
mõnitama, pilkama; võlts, teeseldud
Mock erineb stubist või spyst, sest seda saab seadistada enne, kui kood käivitatakse. See tähendab, et saab seada üles eeldusi ja pärast testida, kas need peavad paika:
it("mocks schedule", () => {
const mockObj = sinon.mock(schedule);
const expectation = mockObj.expects("classIsFull").once();
student.addClass(schedule);
expectation.verify();
});
Mock võimaldab testida küllalt keerulisi stsenaariume ning enamikel juhtudel pole vaja mocki kasutada. Enamik kasutajaid saab oma testid tehtud kasutades stube.
Kogu kood:
"use strict";
const sinon = require("sinon");
describe("sinon tests", () => {
let student, schedule;
beforeEach(function() {
student = {
dropClass: function(classId, cb) {
//do stuff
if (!!cb.dropClass) {
cb.dropClass();
} else {
cb();
}
},
addClass: function(schedule) {
if (!schedule.classIsFull()) {
return true;
} else {
return false;
}
}
};
schedule = {
dropClass: function() {
console.log("class dropped");
},
classIsFull: function() {
return true;
}
};
});
describe("sinon", function() {
it("should call the callback", () => {
const spy = sinon.spy();
student.dropClass(1, spy);
spy.called.should.be.true;
});
it("should call the callback and log to the console", () => {
function onClassDropped() {
console.log("onClassDropped was called");
}
var spy = sinon.spy(onClassDropped);
student.dropClass(1, spy);
spy.called.should.be.true;
});
it("should call the callback even if it's a method of an object", () => {
sinon.spy(schedule, "dropClass");
student.dropClass(1, schedule);
schedule.dropClass.called.should.be.true;
});
});
describe("stubs", () => {
it("shoud call a stubbed method", () => {
const stub = sinon.stub(schedule);
student.dropClass(1, stub.dropClass);
stub.dropClass.called.should.be.true;
});
it("should return true when the class is not full", () => {
const stub = sinon.stub(schedule);
stub.classIsFull.returns(false);
const returnVal = student.addClass(stub);
returnVal.should.be.true;
});
});
describe("mocks", () => {
it("mocks schedule", () => {
const mockObj = sinon.mock(schedule);
const expectation = mockObj.expects("classIsFull").once();
student.addClass(schedule);
expectation.verify();
});
});
});