TDD Chronicle

by Jesse 6. October 2009 14:14

I just started a new feature and I've seen a lot of questions surrounding "how do I _START_ with tdd?" because, well, sometimes its not straight forward.  So this will be a hot and loose blog post full of screw ups and how it all plays out.  No really, if it don't work the first time ...theeennn it doesn't work.  Anyway, here we go.

My first thought was break out notepad, write out what it should do and how I think it should work.  Here's what I wrote ...

Scheduling Service

When given a schedule and a room
 adding a list of events to that room should occur

and I stopped.  There's more than one type of schedule -- say the user does a one off, and then does a list of 50 (something that recurs) ... so already I need to go back and change stuff as such and had to stop myself again

Event Scheduling Service

When given a single event and a room
 that event should save without a recurId

When given an event range and a room
 that event should save

Should save how?  I have to have days on the list somewhere, so the test is now driving my design, which I'm ok with.  Back tracking a little bit ... I need to include some design details in this and as you may have guessed, I stopped again.  How am I scheduling this?  An event takes place on a certain day so you have a start time and end time but the event in and of itself doesn't span days (not a requirement) so I need a separate pieces of this.  Back to notepad.

Event Scheduling Service

design : Two calendars for range of occurrence
            ListBoxes of Days (mon-sun)
            Two time boxes for start/stop times
            Single day event/recur button (different views?)

When given a single event and a room
 that event should save without a recurId

When given an calendar range, an event, selected days and a room
 that event should save with a recurId and
 that event should

notice the last line ... because it should spawn a whole ton of events ... oh I got it here we go

Event Scheduling Service

design : Two calendars for range of occurrence
  ListBoxes of Days (mon-sun)
  Two time boxes for start/stop times
  Single day event/recur button (different views?)

When given a single event and a room
 that event should save without a recurId
 and that should result in just one event for that room

When given an calendar range, an event, selected days and a room
 that event should save with a recurId and
 that first event's ID should be the recurId and
 that should result in multiple events saved for that room

Alright, now I have some testing criteria.  Using some copy/paste kung fu I get my basic class for testing setup and start writing my first test.

public void AndWhenSavingASingleEventIShouldNotHaveARecurIDAndOnlyAddOne()
{

Completely ignoring the class name, um, wow, that's one hell of a method name, even for me.  WAY too much is going to happen in that -- the "AND" is the big hint, so split it out!  While doing so, I ran into yet another problem ... what's a valid event?!  What's required?  Back to the text file...

Event Scheduling Service

design : Two calendars for range of occurrence
  ListBoxes of Days (mon-sun)
  Two time boxes for start/stop times
  Single day event/recur button (different views?)

a valid single event
 should have a date
 should have a start time
 should have an end time
 should have a room
 should have a title
 should be in the future (duh!)
 could have a org id
 

When given a valid single event and a room
 that event should save without a recurId
 and that should result in just one event for that room

When given an calendar range, a valid event, selected days and a room
 that event should save with a recurId and
 that first event's ID should be the recurId and
 that should result in multiple events saved for that room
 
When given an invalid single event
 that event should not save
 and return an error(? does this break the repository knowledge boundary?)

when given an invalid multiple events
 those events should not save
 and return an error(? again, does this break the boundary rule?)

Woah, now we got some stuff going on here.  So now I have a new test for just the entity and make sure its valid before event attempting to save and raises an interesting question - who should know that the entity is valid?  Because of my background, I go with "who needs to know?" -- the entity does, it should know if its correct or not.  Also notice where I put that data -- above what it should do (the service) so its separate.  So I'll need to add in "IsValid()" off the CalendarEvent object with a boolean return value... no sweat.  I go stub out a IsValid as such...

public virtual bool IsValid()
{
     throw new NotImplementedException();
}

And I create a test as such to test the first one on my list ...and ran face first into a problem.  The current database model doesn't support this.  So now I have a database issue on top of everything else.  Now I'm annoyed.  I have to go BACK into the database, create a new column, etc etc etc.  Even worse, when I go into the database, I see everything is nullable.  Fail.  Put that on the clean-up list.  Anyway, I add a column event_date, and move forward.

Still annoyed by my most recent discovery, I write out my test as such.

[Test]
public void ACalendarEventShouldHaveADate()
{

var eventCal = BuildCalEvent();
eventCal.IsValid().ShouldBeTrue();

eventCal.event_date = null;
eventCal.IsValid().ShouldBeFalse();

}

Assuming (which I don't) that buildcalevent returns a valid object, the first "shouldbetrue" is a sanity test -- otherwise whats the worth in having a test pass when you have invalid data to begin with?  Anyway, got the test, it fails, as it should -- not implemented.  Go implement it!

public virtual bool IsValid()
{
     return (event_date.HasValue);
}

And run out test... and I failed.  I screwed something up.

TestCase '<blahblah>.WhenWorkingWithCalendarEvents.ACalendarEventShouldHaveADate'
failed:
Expected: True
But was: False

Debugger time and HA! It's the sanity check -- I didn't add the data in for my new column!  Ok fine, go fix that and ... yay! Test passes!  So now I'll write out the rest of my tests and spare you the boredom... (DateTime.AddMinutes(10)) ... Ok, no surprise, I ended up with about 7 tests.  I nixed the "could have" because its not part of it being valid and I split out the sanity check to its own test.  Now to write the validation checks one at a time.

Well, I got to my last test and ran into -- you guessed it, another problem.  I smelled an edge case with the "should be in the future" because technically, today isn't in the future ... its now.  Sure enough when I added an event_date as today, it failed.  A quick < to <= and all my tests now pass. The result for the IsValid looks something like this

public virtual bool IsValid()
{
if (!event_date.HasValue)
    
return false;
else if (!event_start.HasValue)
    
return false;
....
else return true;
}

and my tests look something like this ...

[Test]
public void BuildOfEnityShouldBeSanitary()
{
     BuildCalEvent().IsValid().ShouldBeTrue();
}
[Test]
public void ACalendarEventShouldHaveADate()
{
     var eventCal = BuildCalEvent();
     eventCal.event_date =
null;
     eventCal.IsValid().ShouldBeFalse();
}

For now, I'm going to stop here so I can check in what I have -- to be continued!

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Methods

Comments

Powered by BlogEngine.NET 1.4.5.0
Theme by Mads Kristensen

About the author

Like the description says, at my core, I'm a scientist and engineer.  I came from humble beginnings on a 486DX2 Packard Hell playing doom2 on IPX to in a small time retail shop and got into hardware (ISO layers FTW!) and it was all downhill from there.  I'm infinitely curious about almost everything and always wanting to know.

According to personality tests (real ones) I classify under "Rational" more specifically, a Fieldmarshal.  I think there's something to that.

Some of the stuff I'm currently into/researching...

Sitefinity

Ninject

Subsonic 

Currently working on ...
i did the hundred


and some extra stuff

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's, their brother, their dog, cat, ferret nor gold fish's view in anyway.  At all.  Ever.

© Copyright 2007-2009