So I have been making a game up to a point where I want to try TDD, so most of my working code don’t have any test but I would like to try TDD for every new features.
My problem is my game comprises of tons of interdependent systems (sort of like I can’t use the camera without the level in place, objects keep lots of references and initializing things take other things as argument). So just to test the fog system I need to initialize the level, the physic, the camera, the collision (because they all depend on each other to some degrees) and that create lots of duplications. Here’s the code:
test( "shadow test", function() {
var b2world=new b2World(new b2Vec2(0, 0), false);
var contactListener = new collisionHandler.CollisionHandler(MASK_BITS);
b2world.SetContactListener(contactListener);
var map = gamejs.http.load('images/prot8.json');
var level = new Level.Level({
map: map,
size: 0.5,
nMaskBits: MASK_BITS.node,
nCategoryBits: MASK_BITS.player | MASK_BITS.birdy | MASK_BITS.innerBody,
world: b2world,
scale: SCALE});
var cam = new Camera.Camera({
lvlWid: this.level.width*SCALE*this.level.blockSize,
lvlHei: this.level.height*SCALE*this.level.blockSize,
yBand: 2,
maxSpeed: 20,
peerWindow: new b2Vec2(350, 300),
scrWid: scrWid,
scrHei: scrHei});
var shadow = new Shadow.Shadow({
width : 300,
height : 300,
level : level,
eye : new b2Vec2(600, 600),
});
ok( shadow.blit, "Shadow is extended from surface" );
ok( shadow.level, "Shadow has reference to the level" );
ok( shadow.eye, "Shadow has reference to player's eye" );
ok( (function() {
for (var i = 0; i < shadow.onScreenBlocks.length; i++) {
var rect = level.boxes[ shadow.onScreenBlocks[i] ];
//this is half finished
}
return true;
}), "Shadow do picks the blocks that are visible on screen" );
ok( (function() {
for (var i = 0; i < level.boxes.length; i++) if ( shadow.notProcessBlock(i) ) {
var rect = level.boxes[i];
if (rect.left < cam.offsetX //at this point I just realized that camera need to be setup in a more complex way...
}
return true;
}), "Shadow only process those blocks that are visible on screen" );
});
overall it just has a bad vibe to it. It’s harder to wrap my mind around and harder to maintain I think.
When writing unit testing in a non-TDD way, you have to ask yourself for each piece of code you write: ‘How can I test this’. This forces you to look at your code and make sure that all dependencies can be replaced when testing.
When doing TDD, this ‘How can I test this’ is baked in from the beginning. Introducing TDD in the middle of a project leads to problems when you can’t replace all dependencies.
When Unit Testing, you need to make sure that you can test a unit in complete isolation and replace all dependencies with mocks or fakes. Then you can control all the inputs to your unit test so can you make sure that all code paths are tested.
To make unit testing work in your project you will have to refactor your code to really support unit testing.
I think TDD is not the main issue in this case. The question is if you want to use Unit testing at all and I think the answer to that question should be yes! Unit testing has many advantages. Now, you face the problem that the code you have written is hard to test. Making sure your code is testable is something that can be done after you’ve written your code but as you now experience that’s quite hard. That’s the point where TDD can help. TDD will make sure your code is easily testable so you can have all the benefits of unit testing.
I wrote a blog some time ago about unit testing.. maybe it can help: Unit Testing, hell or heaven?