Today I was trying to create a node.js script to test a HTTP service but the test required multiple steps. I gave it a try by using async module to "symplify" that code and that's the ugly code I came up with.
I'm not an expert in js/node, feel free to comment if I'm doing something wrong, I'm more than happy to learn.
(inflightSession and create are two helper functions that I have)
Test using node + jasmine:
it("should accept valid sessionId", function(done) {
async.waterfall([
inflightSession,
function(sessionId, callback) {
create({ 'sessionId':sessionId }, callback);
}
], function(error, response) {
expect(response.statusCode).to.equal(200);
done()
});
});
Same test using python + unittest:
def create_ok_test():
session_id = inflight_session()
response = create({ 'sessionId': session_id })
assert_equals(200, response.status_code)
Same test using node ES6 generators (yield keyword):
it("should accept valid sessionId", function*() {
var sessionId = yield inflightSession();
var response = yield create({ 'sessionId': sessionId });
expect(response.statusCode).to.equal(200);
});
Honestly the code in python is way more readable than the existing node code, and still better even when comparing it with the new node generators. Anway definitely looks like a promising way to move forward in the node community. Some comments:
ES6 generators are available under a flag in node 0.11 and are supposed to be included in 0.12.
yield is a common keyword in other languages (i.e. python, C#) to exit from a function but keeping the state of that function so that you can resume the execution later.
function* is the syntax to define a generator function (a function using yield inside).
You need a runner supporting those generator functions (in this example jasmine needs to add support for it), basically calling the generator.next and waiting for the result (the result should be a promise or similar object) before calling generator.next again.
UPDATE: As I´m somehow forced to use node, I ended up creating a helper function and my tests are now like this
itx("should accept valid sessionId", inflightSession, function(sessionId, done) {
create({ 'sessionId':sessionId }, function(error, response) {
expect(response.statusCode).to.equal(200);
done()
});
});
With promises you can do something like this (pseudocode):
ResponderEliminarinflightSession
.then(function(sessionId) {
create({sessionId:sessionId});
)
.then(function(response) {
expect(response.statusCode.to.equal(200));
})
.then(done);
It is clearer than async, but not as clear/compact as its sequential alternative in python/java... and most people/libraries still use the callback style.
These two are good resources:
- http://strongloop.com/strongblog/promises-in-node-js-with-q-an-alternative-to-callbacks/
- https://github.com/kriskowal/q
With async is slightly more compact IMO, but I agree that promises can be easier to read. Thx for the comment, very useful.
ResponderEliminarThis is also interesting, based on coroutines https://github.com/visionmedia/co
ResponderEliminar