Recherche…
Assertion de base
À son niveau le plus élémentaire, le test unitaire dans n'importe quel langage fournit des assertions contre certains résultats connus ou attendus.
function assert( outcome, description ) {
var passFail = outcome ? 'pass' : 'fail';
console.log(passFail, ': ', description);
return outcome;
};
La méthode d'assertion courante ci-dessus nous montre un moyen rapide et facile d'affirmer une valeur dans la plupart des navigateurs Web et des interpréteurs comme Node.js avec pratiquement n'importe quelle version d'ECMAScript.
Un bon test unitaire est conçu pour tester une unité de code discrète; généralement une fonction.
function add(num1, num2) {
return num1 + num2;
}
var result = add(5, 20);
assert( result == 24, 'add(5, 20) should return 25...');
Dans l'exemple ci-dessus, la valeur de retour de la fonction add(x, y)
ou 5 + 20
est clairement 25
, donc notre assertion de 24
devrait échouer et la méthode assert enregistrera une ligne "échec".
Si nous modifions simplement notre résultat d'assertion attendu, le test réussira et la sortie résultante ressemblera à ceci.
assert( result == 25, 'add(5, 20) should return 25...');
console output:
> pass: should return 25...
Cette simple assertion peut garantir que dans de nombreux cas différents, votre fonction "Ajouter" renverra toujours le résultat attendu et ne nécessite aucun framework ou bibliothèque supplémentaire pour fonctionner.
Un ensemble d'assertions plus rigoureux ressemblerait à ceci (en utilisant var result = add(x,y)
pour chaque assertion):
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...');
Et la sortie de la console serait la suivante:
> pass: should return 0...
> pass: should return -1...
> pass: should return 1...
Nous pouvons maintenant affirmer que add(x,y)
… devrait retourner la somme de deux entiers . Nous pouvons les transformer en quelque chose comme ceci:
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;
}
}
Test d'unité avec Moka, Sinon, Chai et Proxyquire
Nous avons ici une classe simple à tester qui renvoie une Promise
basée sur les résultats d'un ResponseProcessor
externe qui prend du temps à exécuter.
Pour simplifier, nous supposerons que la méthode processResponse
n'échouera jamais.
import {processResponse} from '../utils/response_processor';
const ping = () => {
return new Promise((resolve, _reject) => {
const response = processResponse(data);
resolve(response);
});
}
module.exports = ping;
Pour tester cela, nous pouvons tirer parti des outils suivants.
J'utilise le script de test
suivant dans mon fichier package.json
.
"test": "NODE_ENV=test mocha --compilers js:babel-core/register --require ./test/unit/test_helper.js --recursive test/**/*_spec.js"
Cela me permet d'utiliser la syntaxe es6
. Il fait référence à un test_helper
qui ressemblera à
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
nous permet d'injecter notre propre stub à la place du ResponseProcessor
externe. Nous pouvons alors utiliser sinon
pour espionner les méthodes de ce stub. Nous utilisons les extensions de chai
que chai-as-promised
injecte pour vérifier que la promesse de la méthode ping()
est fullfilled
et qu'elle renvoie eventually
la réponse requise.
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);
})
});
Supposons maintenant que vous souhaitiez tester quelque chose qui utilise la réponse de ping
.
import {ping} from './ping';
const pingWrapper = () => {
ping.then((response) => {
// do something with the response
});
}
module.exports = pingWrapper;
Pour tester le pingWrapper
nous pingWrapper
Comme précédemment, Proxyquire
nous permet d'injecter notre propre stub à la place de la dépendance externe, en l'occurrence la méthode ping
nous avons testée précédemment. Nous pouvons alors utiliser sinon
pour espionner les méthodes de ce stub et tirer parti de sinon-stub-promise
returnsPromise
pour nous permettre de returnsPromise
. Cette promesse peut alors être résolue ou rejetée comme nous le souhaitons dans le test, afin de tester la réponse de l'enveloppe à cela.
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);
});
});