views:

271

answers:

8

I am making a role playing game for fun and attempting to use TDD while developing it. Many of the TDD examples I see focus on creating the test first, then creating objects that are needed to get the test to pass.

For example:

[Test]
public void Character_WhenHealthIsBelowZero_IsDead()
{
   // create default character with 10 health
   Character character = new Character();
   character.SubtractHealth(20);
   Assert.That(character.IsAlive, Is.EqualTo(false));
}

So based on this I'll create the character class and appropriate properties/methods. This seems fine and all but should my class design really come out of continually refining my tests? Is that better than mapping out the possible objects that my game will need ahead of time? For example, I would normally think of a base Character class, then subclasses such as Wizard, Fighter, Theif.

Or is a balanced approach the way to go? One where I map out the possible classes and hierarchy I'll need but writing tests first to verify they are actually needed?

+5  A: 

I think it's generally assumed (even by the TDD purists) that a programmer designing an application by writing tests already knows something about design and architecture. Otherwise you can just paint yourself into programming chaos and anarchy by writing tests to the abandonment of any design principles.

Consequently, a developer writing an application "tests first" already has a fair idea of what his final class structure will look like, and that vision guides him when he is writing his tests.

Robert Harvey
While I agree that there's an assumption that the developer understands design principles, I believe the tests can help guide your design. For instance, loose coupling should come naturally.
TrueWill
+1  A: 

TDD is about letting the tests drive your design, including your class design. This is valuable because the tests are meant to prove that the code "works". That means you'll wind up with a class design of a program that works, as opposed to a class design of a program which may or may not work.

John Saunders
+5  A: 

I think you're missing the point of TDD. TDD is not about writing tests - it's about designing your classes to be testable. This naturally leads to a better design and implementation.

It sounds like you're doing it backwards.

Your steps should be:

  1. Design your domain model
  2. Design your classes
  3. Write some tests
  4. Implement some class logic
  5. Refactor your classes to make them more testable where necessary
  6. Repeat Steps 3-5
womp
"Designing" the classes may or may not be necessary, depending on your experience level. I almost never have a separate design step.
John Saunders
@Joh Saunders - You're still designing them in all likelihood, you're just embracing "Just in time" design. I think it's important to separate JIT design from lack of design. TDD strongly infers (deliberate understatement) good class design at least from a separation of concerns/encapsulation perspective. Instead of UML or whatever, your class design just happens to be documented in your test syntax. You hit the nail on the head with "depending on your exp"... for someone newer, some form of explicit design step may be a good idea.
Jim Leonardo
@Jim: I was responding to those who think of "class design" the old-fashioned way, requiring a separate design step, with artifacts, UML, etc. Of course there's design with TDD, but not a separate design step. This can cause Project Managers to be unhappy that there's not a separate bucket to bill "design" hours to.
John Saunders
@John - old fashioned? Perhaps, but as almost any BA will tell you, still required a good portion of the time. I'm in a small, technologically progressive company and we still architect portions of our frameworks with class diagrams.
womp
@womp: all those BA's out there haven't yet told me class design is required. Maybe they're too intimidated to tell me?
John Saunders
+1  A: 

I think the balanced approach is the one you need to take. First model the classes of your domain, because without them, how do you even know what to test?

Then, you'll probably create stubs or shells of these classes, with mostly empty implementations, just to let you write some test structures.

Once that's done, your test cases will likely illuminate the need for new methods / classes / properties that weren't in the original design, but are discovered as being necessary.

FrustratedWithFormsDesigner
A: 

A balanced approach is the way to go.

However, the balance is Driven by the need to test.

You can map out the possible classes and hierarchy. But, you'll need to drive the design by (1) thinking about testability and (2) writing the tests before writing too much code.

For your tests to even compile, you need some class definitions. They don't have to work, but they have to compile.

In a few cases your class may be so simple, you actually write all (or almost all) of it first.

S.Lott
A: 

TDD is about design! So doing TDD you will be sure that your design is completely testable.

Also, the "balanced approach" is the way to go IMO. You already know a high level architecture and TDD will drive this architecture to be testable.

EDIT: Although, if you want just to practice TDD I would not do the "balanced approach". I would just do TDD with "baby steps" and maybe coding Dojos

Diego Dias
A: 

TDD leans toward thinking about and experimenting with class design concretely using running code rather than abstractly with pencil and paper.

Both approaches are useful. Even hardcore TDD zealots use pencil-and-paper (or perhaps a whiteboard) at times, and BDUF-ueber-alles types will bang out the occasional prototype. The question then is where you tend to fall: ponderer or more hands-on?

Greg Bacon
+6  A: 

Should my class design really come out of continually refining my tests?

Yes.

Does TDD mean not thinking about class design?

Absolutely not. It means thinking about class design in the course of writing your tests, and the rest of your code. Class design is at play throughout the Red-Green-Refactor TDD life cycle.

Carl Manaster