Tuesday, April 10, 2007

Books

Two failing tests
 testCanonicalAbilitiesReturnsTestAbility and TestLisaReadingABookHasNoEffect. In each case, I have a choice, either to remove the test or fix it.

testCanonicalAbilitiesReturnsTestAbility
 This can probably be removed, but for now, it's easy enough to fix it. I was using a variable for two different purposes, which is easily remedied. A few tweaks, and it's passing.

TestLisaReadingABookHasNoEffect
 Ok, the problem here was the test only checked to see if any effects were returned. In this case, we want the effect to be returned, but we don't want it to do anything to Lisa (who is already at max intelligence). Fixed the test (to really test for what we wanted), and it passes. Joe's test (was named TestJoeReadingABookHasNoEffect, which I've fixed to be TestJoeReadingABookMakesHimSmarter) also passes.
 I'm being a little lazy in how I test. I'm checking to make sure that a character has changed, but not looking too deeply into what has changed (in this case, it should be intelligence). I'll add this to my refactorings (along with a general test audit for relevance).

All tests pass, now what?
 The fork in the road ahead is refactoring or adding functionality. No significant smells (not completely oderless, of course), so I'm leaning towards functionality.
 So far, I have Charcters (Homer, Lisa, Joe), Statistics (Strength, Intelligence), Abilities (Read Book), and Effects(Increase Statistic). The next thing I want to add is Items (Book). The general idea is that you can't read a book without actually having the book in your hands. There are a few ways to implement this.
 One way: When a character gets an item, they also get the associated Abilities. When the item is removed, those abilities should also be removed. Hmm... well, only if there aren't any other items that also use those same abilities. That's a lot of synchronization.
 Another way: Make the abilities part of the item. That is, the character may have some intrinsic abilities (e.g. "Smile") that do not require any items. Additionally, each item may have some abilities (e.g. Book."Read") that they grant to the user. I like this way better.
 I'll start with a simple test, testGiveHomerABook. Hmm... Actually, I'll start with a simpler test - testCreateBook. Ok, both tests fail, time to starting writing.

CItem
 First, create a new class of Item. Ok, that makes this test pass. I feel like I'm going to want to use this book quite a bit, so I'm going to add it to my global list of parameters. Not really global, just passed to each function. Done.

Character.GiveItem
 Now to implement this function. It's another array of objects, should be straightforward. Done, and tests pass.

Adding Abilities to Book.
 My setup function should add an ability (and the associated effect) to the book. This is going to be a little complicated, so first I'm going to extract SetupCreateBookOfKnowledge() as a sub-method of SetupTests.

Comments
 One of the (many) things that resonated with me from Fowler's Refactoring book is his opinion on code comments. Comments smell nice, but they are usualy used as a deoderant to cover up some other smell. Instead of adding a comment, remove the smell.
 My setupTest functions has a few comments for blocks of code that create Homer, Lisa, and Joe. Each of those can be extracted into a single function SetupCreateGenericCharacter(strName, lngSetAllStatisticsToThisNumber). This also will allow me to get rid of a temporary variable. It's smelling a bit better now.

Joe First
 Refactoring Joe first, and testing...Bug(Undeclared Variable). Fixed, retesting...Everything passes. Now for Homer...Passes. Finally Lisa...Whoa! about ten tests fail, Danger, Will Robinson! Oh, I accidentally created another Homer. Fixed. Phew, all tests pass. Final step, cleaning up unused variables (and redundant comments). Excellent, tests pass.
 That was a nice little bit of refactoring that will allow me to add more test characters as needed. Cool. And it flowed naturally from functionality I was adding.

Back to Books
 Ok, now I'm moving this SetupCreateBookOfKnowledge function to my main test page to take advantage of Intellisense. I've improved the book by adding an ability. However, I don't have any tests that reflect that, so I don't really know if it's working (even though all tests are written). I, once again, failed to write tests first.