Suche…
Grundsätzliche Behauptung
Auf der untersten Ebene bietet Unit Testing in einer beliebigen Sprache Aussagen gegen bekannte oder erwartete Ergebnisse.
function assert( outcome, description ) {
var passFail = outcome ? 'pass' : 'fail';
console.log(passFail, ': ', description);
return outcome;
};
Die oben genannte beliebte Assertionsmethode zeigt uns eine schnelle und einfache Möglichkeit, einen Wert in den meisten Webbrowsern und Interpreters wie Node.js mit praktisch jeder Version von ECMAScript zu bestätigen.
Ein guter Unit-Test dient zum Testen einer diskreten Code-Einheit. normalerweise eine Funktion.
function add(num1, num2) {
return num1 + num2;
}
var result = add(5, 20);
assert( result == 24, 'add(5, 20) should return 25...');
Im obigen Beispiel ist der Rückgabewert der Funktion add(x, y)
oder 5 + 20
eindeutig 25
, daher sollte unsere Zusicherung von 24
fehlschlagen, und die Assert-Methode protokolliert eine "Fail" -Zeile.
Wenn wir einfach unser erwartetes Assertionsergebnis ändern, wird der Test erfolgreich sein und die resultierende Ausgabe würde ungefähr so aussehen.
assert( result == 25, 'add(5, 20) should return 25...');
console output:
> pass: should return 25...
Diese einfache Behauptung kann sicherstellen, dass Ihre Funktion "Hinzufügen" in vielen verschiedenen Fällen immer das erwartete Ergebnis zurückgibt und keine zusätzlichen Frameworks oder Bibliotheken erfordert.
Ein strengerer Satz von Zusicherungen würde folgendermaßen aussehen (mit var result = add(x,y)
für jede Zusicherung):
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...');
Und die Konsolenausgabe wäre folgendes:
> pass: should return 0...
> pass: should return -1...
> pass: should return 1...
Wir können nun mit Sicherheit sagen, dass add(x,y)
… die Summe zweier Ganzzahlen ergibt . Wir können diese in so etwas aufrollen:
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;
}
}
Unit-Testversprechen mit Mocha, Sinon, Chai und Proxyquire
Hier haben wir eine einfache zu testende Klasse, die ein Promise
zurückgibt, basierend auf den Ergebnissen eines externen ResponseProcessor
, dessen Ausführung Zeit erfordert.
Der Einfachheit halber gehen wir davon aus, dass die processResponse
Methode niemals fehlschlagen wird.
import {processResponse} from '../utils/response_processor';
const ping = () => {
return new Promise((resolve, _reject) => {
const response = processResponse(data);
resolve(response);
});
}
module.exports = ping;
Um dies zu testen, können wir die folgenden Tools nutzen.
Ich verwende den folgenden test
in meiner package.json
Datei.
"test": "NODE_ENV=test mocha --compilers js:babel-core/register --require ./test/unit/test_helper.js --recursive test/**/*_spec.js"
Dadurch kann ich die es6
Syntax verwenden. Es verweist auf einen test_helper
, der aussehen wird
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
ermöglicht es uns, anstelle des externen ResponseProcessor
eigenen Stub zu injizieren. Wir können dann mit sinon
die Methoden dieses Stubs ausspionieren. Wir verwenden die Erweiterungen chai
, dass chai-as-promised
einspritzt zu überprüfen, ob die ping()
Methode Versprechen ist fullfilled
, und dass es eventually
liefert die erforderliche Antwort.
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);
})
});
Nehmen wir stattdessen an, Sie möchten etwas testen, das die Antwort von ping
.
import {ping} from './ping';
const pingWrapper = () => {
ping.then((response) => {
// do something with the response
});
}
module.exports = pingWrapper;
Um den pingWrapper
zu testen, pingWrapper
wir ihn
Nach wie vor erlaubt Proxyquire
, Proxyquire
der externen Abhängigkeit einen eigenen Stub zu injizieren, in diesem Fall die zuvor getestete ping
Methode. Wir können dann sinon
um die Methoden dieses Stubs auszuspionieren und das sinon-stub-promise
zu nutzen, um uns die returnsPromise
sinon-stub-promise
zu ermöglichen. Dieses Versprechen kann dann wie gewünscht im Test gelöst oder abgelehnt werden, um die Antwort des Wrappers darauf zu testen.
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);
});
});