UnabhÀngige Unit-Tests: HTTP-Anfragen abstrahieren
Das Erzeugen und Verwenden von Stub- und Mock-Objekten fĂ€llt in JavaScript aufgrund des dynamischen Typsystems verhĂ€ltnismĂ€Ăig leicht. Aufwendig wird es allerdings, wenn eine gewisse KomplexitĂ€t erreicht wird, wie beim Simulieren des HTTP-Protokolls. Warum also nicht fĂŒr derartige Aufgaben ein spezialisiertes Framework verwenden?
Um Komponenten unabhĂ€ngig voneinander testen zu können, greift man in der Regel auf Stub- und Mock-Objekte zurĂŒck. JavaScript und auch Node.js bilden hierzu keine Ausnahme. Aus diesem Grund existieren diverse Frameworks, die den Entwickler beim Erzeugen und Verwenden dieser Objekte unterstĂŒtzen, beispielsweise das Ă€uĂerst empfehlenswerte Sinon.js [1].
Dennoch kann es sinnvoll sein, fĂŒr ausgewĂ€hlte Szenarien spezialisierte Frameworks einzusetzen. Ein derartiges Framework ist nock [2], das von Pedro Texeira entwickelt wird und auf das Simulieren von HTTP-Anfragen spezialisiert ist.
Die Installation von nock erfolgt auf dem ĂŒblichen Weg mit npm (Node Package Manager) in den lokalen Kontext der Anwendung:
$ npm install nock
AnschlieĂend kann man die require-Funktion aufrufen, um das Modul in die eigenen Unit-Tests zu integrieren:
var nock = require('nock');
HTTP-Anfragen abfangen
Um eine HTTP-Anfrage zu simulieren, muss man nock im nĂ€chsten Schritt die Adresse des zu simulierenden Webservers ĂŒbergeben und fĂŒr die Kombination aus verwendeter Methode und Route die gewĂŒnschte Antwort hinterlegen. Um beispielsweise zu simulieren, dass das HinzufĂŒgen eines neuen Anwenders funktioniert hat, genĂŒgt der folgende Code:
nock('http://api.example.com')
.post('/users', { lastName: 'Roden', firstName: 'Golo' })
.reply(201, { id: 'e204e508-10a5-4d38-86fe-35e4de99a79e' });
Stellt die Anwendung nun eine passende Anfrage an die genannte Adresse, fĂ€ngt nock diese Anfrage ab und reagiert, indem es den Statuscode "201" und die angegebene ID als JSON-Objekt zurĂŒcksendet.
Nachdem nock reagiert hat, markiert es die Anfrage als beantwortet. Wenn die Anwendung die gleiche Anfrage zu einem spÀteren Zeitpunkt erneut stellt, lÀsst nock sie passieren. Wenn man auch diese zweite Anfrage abfangen will, muss man nock mehrfach mit der gleichen Konfiguration aufrufen.
Anstelle eines JSON-Objekts kann man bei Bedarf alternativ eine Zeichenkette ĂŒbergeben, oder â wenn man statt reply die Funktion replyWithFile verwendet â auch eine beliebige Datei.
HTTPS, Ports und Verben verwenden
Um statt einer HTTP- eine HTTPS-Anfrage zu simulieren, genĂŒgt es, nock eine HTTPS-Adresse zu ĂŒbergeben. ZusĂ€tzlich kann man auch einen alternativen Port angeben, um einen anderen als den standardmĂ€Ăig vorgesehenen Port 80 beziehungsweise 443 zu verwenden.
AuĂer der Funktion post stellt nock weitere Funktionen zur VerfĂŒgung, die auf verschiedene andere HTTP-Verben reagieren: get, put, delete, head, patch und merge. DarĂŒber hinaus ist es möglich, auf jedes beliebige Verb zu reagieren, indem man die Funktion intercept verwendet, und dieser als zweiten Parameter das gewĂŒnschte Verb ĂŒbergibt:
nock(...).intercept('/', 'OPTIONS').reply(...);
Ausgesprochen hilfreich ist, dass man sÀmtliche Funktionen von nock verketten kann, also mehrere Anfragen an einen Webserver auf einmal konfigurieren kann:
nock(...)
.get(...).reply(...)
.post(...).reply(...);
Erwartungen formulieren
Innerhalb eines Unit-Tests kann es durchaus interessant sein, ob eine HTTP-Anfrage gestellt wurde oder nicht. Zu diesem Zweck liefert der Aufruf von nock ein Objekt zurĂŒck, das entsprechende Funktionen anbietet. Die wichtigste dieser Funktionen ist isDone. Sie gibt true zurĂŒck, wenn die zugehörige HTTP-Anfrage gestellt wurde, ansonsten false:
var nockedHttpRequest = nock(...).post(...).reply(...);
if (!nockedHttpRequest.isDone()) {
// ...
}
Die Eigenschaft pendingMocks enthĂ€lt im Fall, dass isDone den Wert false zurĂŒckliefert, eine Liste aller nicht aufgerufenen HTTP-Anfragen:
var nockedHttpRequest = nock(...).post(...).reply(...);
if (!nockedHttpRequest.isDone()) {
console.log(nockedHttpRequest.pendingMocks);
}
Nach dem AbschlieĂen eines Unit-Tests empfiehlt es sich, die Funktion cleanAll aufzurufen, um die Simulation aller zwar registrierten, aber nicht abgerufenen HTTP-Anfragen zu entfernen. Nach diesem Aufruf bleibt nock unsichtbar, bis erneut zu simulierende HTTP-Anfragen registriert werden. Es bietet sich daher an, den Aufruf dieser Funktion innerhalb von suiteTeardown unterzubringen:
suite('...', function () {
var nockedHttpRequest;
test('...', function (done) {
nockedHttpRequest = nock(...).post(...).reply(...);
// ...
done();
});
suiteTeardown(function () {
nockedHttpRequest.cleanAll();
});
});
Auf diesem Weg findet jeder Unit-Test einen aufgerĂ€umten Zustand vor und kann nock an die individuellen BedĂŒrfnisse anpassen.
tl;dr: Das Modul nock ist ein unverzichtbares Hilfsmittel, um Code zu testen, der HTTP-Anfragen stellt. Man kann jede einzelne Anfrage simulieren und anschlieĂend prĂŒfen, ob sie tatsĂ€chlich gestellt wurde. Als spezialisiertes Framework stellt nock daher eine ausgezeichnete ErgĂ€nzung zu Mock-Frameworks wie Sinon.js dar. ( [3])
URL dieses Artikels:
https://www.heise.de/-1942338
Links in diesem Artikel:
[1] http://sinonjs.org/
[2] https://github.com/flatiron/nock
[3] mailto:webmaster@goloroden.de
Copyright © 2013 Heise Medien