Wednesday, January 27, 2010

The Vetrinary Admin: Linking TDD Kata to creating user stories

Today is my 12th day of doing the TDD kata experiment. Mostly it has been with the Calculator kata, but I've started experimenting with creating new katas. First was a Model-View-Presenter kata with mocks, but I am now taking this one step further.

What the TDD kata makes obvious is the practise of writing tests based on a user story.

Historically I am more accustomed to working from a detailed requirements spec, which the last few years has tended to look like this:

1) Read the spec
2) Create a domain model and NHibernate mappings, to database tables which typically were created previously (legacy code or a previous phase).
3) Figure out how the spec translates into distribution across the domain model objects.
4) Write unit tests for various domain model methods as you create them

Not fully test first, more like test middle. And the domain model tends to be mapped fairly closely to the database tables, so the domain entities tend to grow.

But that's a discussion for a whole other blog post. My purpose here is let the TDD kata approach (getting direction from a user story) be my opportunity to practice creating tests directly from user stories.

I've started reading User Stories Applied by Mike Cohn, and I've decided to try some experiments with TDD kata by creating a list of user stories (eg. for a vetrinarian administrator), choosing one of the user stories to write out, and then building a TDD kata based on that story.

Here is today's example, for the vetrinarian administrator:

5 User Stories
#1 - Vet admin can enter pet details (register the pet)
#2 - Vet admin can log a single pet visit
#3 - Vet admin can track and add medications for a pet
#4 - Vet admin can create an invoice for the visit
#5 - Vet admin can create a purchase order for specialized pet foods

[Edit - adding more user story details]
#1 Vet admin can enter pet details (register the pet)
a) Can enter pet with name, breed, age, temperment, and brief health history.
b) Can enter owner name and address (if new).
c) Can associate the owner to the pet (add to owner's list of pets)

#2 Vet admin can log a single pet visit
a) Vet admin can create a pet visit record.
b) Vet admin can enter the comments provided by the vet about the visit
c) Vet admin can add a list of new prescriptions to the pet's prescription list, and link them to this visit.
d) Vet admin can issue a receipt for payment.
[end Edit.]

If I take the 3rd user story, I then write it out in detail:

#3 Vet admin can track pet medications
a) Vet admin can search for medications by name
b) Vet can assign found medication to Fluffy the dog's record
c) If Fluffy has allergy to the newly assigned medication, a flag will be raised
d) If new medication has contraindications with Fluffy's existing meds, a flag will be raised.
e) If flag is raised, vet admin must get Vet override before adding
f) Vet admin can enter prescription date, dosage instructions
g) Vet admin can print prescription.

Now, obviously this user story is too big for a 30 minute TDD kata, but it's a place for me to get started. My hope was that I could just address the domain in my kata, but the user story already includes a medication lookup, which is probably a repository query, so I decided to build the tests at the Model-View-Presenter level with mocked repository and view.

In 30 minutes, I managed to complete only the first step:


[TestFixture]
public class MedicationTrackerPresenterTests
{
private MockRepository _mockRepository;
private IMedicationTrackerView _medicationTrackerView;
private IMedicationRepository _medicationRepository;

[SetUp]
public void SetUp()
{
_mockRepository = new MockRepository();
_medicationTrackerView = _mockRepository.StrictMock();
_medicationRepository = _mockRepository.StrictMock();
}

[TearDown]
public void TearDown()
{
_mockRepository.ReplayAll();
_mockRepository.VerifyAll();
}

[Test]
public void VetAdminCanSearchForMedicationsByName()
{
_medicationTrackerView.SearchEvents += null;
var searchMedicationsEventRaiser = LastCall.IgnoreArguments().GetEventRaiser();
const string searchInput = "Tylenol";
var medications = new List();
Expect.Call(_medicationTrackerView.SearchInput).Return(searchInput).IgnoreArguments();
Expect.Call(_medicationRepository.FindMedicationsByName(searchInput)).Return(medications);
_medicationTrackerView.MedicationsSearchResult = medications;

_mockRepository.ReplayAll();

var medicationTrackerPresenter = new MedicationTrackerPresenter(_medicationRepository, _medicationTrackerView);
searchMedicationsEventRaiser.Raise(_medicationTrackerView, EventArgs.Empty);
}
}


Tomorrow, I will go back to Calculator kata (every 2nd day at least). But this process of going from application concept, to a list of user stories, to fleshing out 1 user story, to building the tests for that story as a TDD kata, feels like a strong practise that I want to reinforce.

No comments: