Jeder, der schon einmal eine Webanwendung entwickelt hat, weiß, dass man viel Zeit in einem Browser verbringt, um zu prüfen, ob alles gut funktioniert und gut aussieht. Und Sie möchten sicherstellen, dass sie in allen möglichen Situationen gut aussieht. Für eine einseitige Anwendung, die mit einem Framework wie AngularJS erstellt wurde und die alle Daten von einem REST-Backend bezieht, bedeutet dies, dass Sie Ihr Frontend anhand verschiedener Antworten von Ihrem Backend überprüfen sollten. Bei einer kleinen Anwendung, die hauptsächlich GET-Anfragen zur Anzeige von Daten enthält, reicht es vielleicht aus, wenn Sie mit Ihrem echten (Entwicklungs-) Backend testen. Aber für große und komplexe Anwendungen müssen Sie Ihr Backend nachbilden. In diesem Beitrag gehe ich im Detail darauf ein, wie Sie dieses Problem lösen können, indem Sie GET-Anfragen für eine AngularJS-Webanwendung nachbilden, die mit Grunt erstellt wurde.
In unserem aktuellen Projekt entwickeln wir ein neues mobiles Frontend für eine bestehende Webanwendung. Das ist sehr praktisch, denn das Backend existiert bereits mit allen REST-Diensten, die wir benötigen. Ein noch größerer Vorteil ist, dass das Team, das die bestehende Webanwendung entwickelt hat, auch eine komplette Mock-Implementierung des Backends erstellt hat. Diese Scheinimplementierung liefert Standardantworten für jede mögliche Anfrage.
Großartig für unsere Protractor End-to-End-Tests! (Vielleicht ein anderer Beitrag darüber an einem anderen Tag.) Aber diese Mock-Implementierung ist nicht so toll für die nicht standardmäßigen Szenarien. Denken Sie an Fehlermeldungen, unvollständige Daten, große Zahlen oder eine merkwürdige Valuta. Wie können wir sicherstellen, dass unsere Benutzeroberfläche diese Fälle korrekt anzeigt? Normalerweise decken wir all diese Fälle in unseren Unit-Tests ab, aber manchmal möchte man sie auch einfach direkt vor sich sehen. Also haben wir begonnen, eine einfache Lösung direkt in unserer Grunt-Konfiguration zu erstellen.
Damit diese Lösung funktioniert, müssen wir dafür sorgen, dass alle unsere REST-Anfragen über die Webserver-Schicht von Grunt laufen. Unsere Webanwendung wird von Grunt auf localhost port 9000 bedient. Dies ist die Standardkonfiguration, die Yeoman generiert (Sie sollten Yeoman wirklich verwenden, um Ihr Projekt zu strukturieren).
Unser Entwicklungs-Backend läuft ebenfalls auf localhost, aber auf Port 5000. In unserer Webanwendung möchten wir alle REST-Aufrufe über den Pfad
[javascript]
livereload: {
options: {
open: true,
middleware: function (connect, options) {
return [
require('connect-modrewrite')(['^/api https://xebia.com/blog:5000/api [P L]']),
/* The lines below are generated by Yeoman */
connect.static('.tmp'),
connect().use(
'/bower_components',
connect.static('./bower_components')
),
connect.static(appConfig.app)
];
}
}
},
[/javascript]
Machen Sie dasselbe auch für den Abschnitt connect:test. Da wir hier 'connect-modrewrite' verwenden, müssen wir dies zu unserem Projekt hinzufügen:
npm install connect-modrewrite --save-dev
Mit dieser Konfiguration wird jede Anfrage, die mit xebia.com/blog:9000/api beginnt, an xebia.com/blog:5000/api weitergeleitet, so dass wir in unserer AngularJS-Anwendung einfach /api verwenden können. Nun, da dies funktioniert, können wir eine benutzerdefinierte Middleware schreiben, um einige unserer Anfragen zu simulieren. Nehmen wir an, wir haben eine GET-Anfrage /api/user, die einige JSON-Daten zurückgibt:
[javascript]
{"id": 1, "name":"Bob"}
[/javascript]
Now we'd like to see what happens with our application in case the name is missing:
[javascript]
{"id": 1}
[/javascript]
Es wäre schön, wenn wir eine einfache POST-Anfrage senden könnten, um die Antwort aller nachfolgenden Aufrufe zu ändern. Etwas wie dies:
curl -X POST -d '{"id": 1}' xebia.com/blog:9000/mock/api/user
Wir haben dem Pfad, den wir nachahmen wollen, /mock vorangestellt, um zu wissen, wann wir mit dem Nachahmen beginnen sollten. Schauen wir uns an, wie wir das umsetzen können. In der gleichen Gruntdatei, die unsere Middleware-Konfiguration enthält, fügen wir eine neue Funktion hinzu, die uns beim Mocking unserer Anfragen helfen wird.
[javascript]
var mocks = [];
function captureMock() {
return function (req, res, next) {
// match on POST requests starting with /mock
if (req.method === 'POST' && req.url.indexOf('/mock') === 0) {
// everything after /mock is the path that we need to mock
var path = req.url.substring(5);
var body = '';
req.on('data', function (data) {
body += data;
});
req.on('end', function () {
mocks[path] = body;
res.writeHead(200);
res.end();
});
} else {
next();
}
};
}
[/javascript]
Und wir müssen die obige Funktion zu unserer Middleware-Konfiguration hinzufügen:
[javascript]
middleware: function (connect, options) {
return [
captureMock(),
require('connect-modrewrite')(['^/api https://xebia.com/blog:5000/api [P L]']),
connect.static('.tmp'),
connect().use(
'/bower_components',
connect.static('./bower_components')
),
connect.static(appConfig.app)
];
}
[/javascript]
Unsere Funktion wird für jede eingehende Anfrage aufgerufen. Sie erfasst jede Anfrage, die mit /mock beginnt, als Anfrage, um eine Mock-Anfrage zu definieren. Anschließend speichert sie den Body in der Variable mocks mit dem Pfad als Schlüssel. Wenn wir also unsere curl POST-Anfrage ausführen, erhalten wir in unserem mocks-Array etwas wie dieses:
[javascript]
mocks['/api/user'] = '{"id": 1}';
[/javascript]
Als nächstes müssen wir diese Daten für Anfragen an xebia.com/blog:9000/api/user zurückgeben. Lassen Sie uns dafür eine neue Funktion erstellen.
[javascript]
function mock() {
return function (req, res, next) {
var mockedResponse = mocks[req.url];
if (mockedResponse) {
res.writeHead(200);
res.write(mockedResponse);
res.end();
} else {
next();
}
};
}
[/javascript]
And also add it to our middleware.
[javascript]
...
captureMock(),
mock(),
require('connect-modrewrite')(['^/api https://xebia.com/blog:5000/api [P L]']),
...
[/javascript]
Großartig, jetzt haben wir eine einfache Mocking-Lösung in nur wenigen Codezeilen, mit der wir einfache POST-Anfragen an unseren Server mit den Anfragen, die wir nachahmen wollen, senden können. Allerdings können nur Statuscodes von 200 gesendet werden und es kann nicht zwischen verschiedenen HTTP-Methoden wie GET, PUT, POST und DELETE unterschieden werden. Lassen Sie uns unsere Funktionen ein wenig ändern, um auch diese Funktionalität zu unterstützen.
[javascript]
var mocks = {
GET: {},
PUT: {},
POST: {},
PATCH: {},
DELETE: {}
};
function mock() {
return function (req, res, next) {
if (req.method === 'POST' && req.url.indexOf('/mock') === 0) {
var path = req.url.substring(5);
var body = '';
req.on('data', function (data) {
body += data;
});
req.on('end', function () {
var headers = {
'Content-Type': req.headers['content-type']
};
for (var key in req.headers) {
if (req.headers.hasOwnProperty(key)) {
if (key.indexOf('mock-header-') === 0) {
headers[key.substring(12)] = req.headers[key];
}
}
}
mocks[req.headers['mock-method'] || 'GET'][path] = {
body: body,
responseCode: req.headers['mock-response'] || 200,
headers: headers
};
res.writeHead(200);
res.end();
});
}
};
};
[/javascript]
[javascript]
function mock() {
return function (req, res, next) {
var mockedResponse = mocks[req.method][req.url];
if (mockedResponse) {
res.writeHead(mockedResponse.responseCode, mockedResponse.headers);
res.write(mockedResponse.body);
res.end();
} else {
next();
}
};
}
[/javascript]
Wir können jetzt erweiterte Mocks erstellen:
curl -X POST
-H "mock-method: DELETE"
-H "mock-response: 403"
-H "Inhaltstyp: application/json"
-H "mock-header-Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT"
-d '{"Fehler": "Nicht autorisiert"}' https://xebia.com/blog:9000/mock/api/user
curl -D - -X DELETE https://xebia.com/blog:9000/api/user
HTTP/1.1 403 Verboten
Inhalt-Typ: application/json
zuletzt geändert: Tue, 15 Nov 1994 12:45:26 GMT
Datum: Wed, 18 Jun 2014 13:39:30 GMT
Verbindung: keep-alive
Transfer-Encoding: chunked
{"Fehler": "Nicht autorisiert"}
Da wir dachten, dass dies für andere Entwickler nützlich sein könnte, haben wir beschlossen, all dies als Open-Source-Bibliothek auf GitHub und NPM zur Verfügung zu stellen:
npm install mock-rest-request --save-dev
Und natürlich fügen Sie es zu Ihrer Middleware-Konfiguration hinzu:
[javascript]
middleware: function (connect, options) {
var mockRequests = require('mock-rest-request');
return [
mockRequests(),
connect.static('.tmp'),
connect().use(
'/bower_components',
connect.static('./bower_components')
),
connect.static(appConfig.app)
];
}
[/javascript]
Verfasst von

Lammert Westerhoff
Unsere Ideen
Weitere Blogs
Contact



