I finished up with vows.js testing of the fab.js libraries in my (fab) game. I finished, but I feel as though the tests are trying very hard to tell me that I need to tidy up a thing or two.
First up, I think the name of my last (fab) app is questionable:
unary_try
. Two uses of this function are:( /move/ )The "unary" part reflects that it generates a unary, or upstream (fab) app. The "try" part of the name indicates that the function passed in gets called if there is a body POSTed by the browser. The "try" is also because there is a
( unary_try( function () {
update_player_status(JSON.parse(""+this));
broadcast(comet_walk_player(this));
} ) )
( /chat/ )
( unary_try( function () {
var msg = JSON.parse(this.toString());
msg.body = msg.say.substr(0,100);
broadcast(comet_player_say(JSON.stringify(msg)));
} ) )
try
-catch
-finally
block around the supplied function.Ugh. Neither of those really help me figure out what this function does when I use it. The name describes what it is more than what it does. Specifically, it invokes the supplied function if there is a POSTed body. Maybe
call_if_body
? Better yet, if_body
:( /move/ )Hmmm... I kinda like that. It is an app that invokes the supplied function if there is a POSTed body. I let the convention of fab indentation indicate that this produces a unary app. The "try" is now incidental part of the implementation.
( if_body(
function () {
update_player_status(JSON.parse(""+this));
broadcast(comet_walk_player(this));
} ) )
( /chat/ )
( if_body(
function () {
var msg = JSON.parse(this.toString());
msg.body = msg.say.substr(0,100);
broadcast(comet_player_say(JSON.stringify(msg)));
} ) )
The next thing that is bothering me is the topic of my vows.js test for this app. I have three different topics in my spec... for six tests. That would not be so bad if the three different topics were significantly different:
callback_when_send_obj: function(obj) {The three different topic generators reflect wanting to test the function supplied to
return function () {
var topic = this;
var upstream_listener = if_body(
function(obj) { topic.callback(null, obj); }
).call(function() {});
upstream_listener(obj);
};
},
downstream_when_exception: function() {
return function () {
var topic = this;
var upstream_listener = if_body(
function() { throw "Foo!"; }
).call(
function(obj) { topic.callback(null, obj); }
);
upstream_listener({body:"foo"});
};
},
downstream_when_send_obj: function(obj) {
return function () {
var topic = this;
var upstream_listener = if_body(
function() {}
).call(
function(obj) { topic.callback(null, obj); }
);
upstream_listener(obj);
};
}
if_body
and the response from if_body
given various inputs (including a thrown exception). Normally, I do not care about DRY in test code, but those are not tests—just API calls. Besides, I am not fond of any of the names of those API calls. Maybe DRYing them up will suggest better naming and usage.I start with the last two API calls that are used for testing downstream responses. The vows.js callback goes in the same place for both—where the downstream app would go in a real fab.js application. I can combine them into a single function that takes the data being POSTed to the resource as the first argument and an optional second argument that is the callback invoked
if_body
:function downstream_response(obj, fn) {I have renamed the helper function as
if (!fn) fn = function() {};
return function () {
var topic = this;
var upstream_listener = if_body(fn).
call(function(obj) { topic.callback(null, obj); });
upstream_listener(obj);
};
};
downstream_response
, which ought to read much better as a vows.js topic. If the if_body
callback is not supplied, then an empty, anonymous function is used. The callback does not affect the response, its only purpose is to change local state. I also rename the other helper function as
args_to_callback
. With those changes, I have vows that read like:'callback, with a body': {I am much happier with that. For each vow, I can readily discern the topic of the test: the args sent to the callback with a POSTed body of "foo", the response downstream with the same POST, and the response when an exception occurs in the callback.
topic: args_to_callback({body: "foo"}),
'invokes callback with body': function(obj) {
assert.equal(obj, "foo");
}
},
'downstream, with a body': {
topic: downstream_response({body: "foo"}),
'terminates connection': function(obj) {
assert.isUndefined(obj);
}
},
//...
'downstream, with exception': {
topic: downstream_response({body: "foo"}, function(){throw "foo";}),
'terminates connection': function(obj) {
assert.isUndefined(obj);
}
}
And all of my tests still pass:
cstrom@whitefall:~/repos/my_fab_game$ vows --spec test/if_body_test.jsThat is a nice stopping point for today. Up tomorrow: poke my head back up to make sure that everything is still working in the game itself. If so, then I will likely look into using vows.js to test some of the state-based portion of the game.
♢ if_body
callback, with a body
✓ invokes callback with body
downstream, with a body
✓ terminates connection
downstream, with HTTP headers
✓ terminates connection
downstream, with empty request
✓ terminates connection
downstream, with exception
✓ terminates connection
✓ OK » 5 honored (0.015s)
Day #160
No comments:
Post a Comment