I’m a huge believer in TDD (test-driven development utilizing a unit testing framework) and do my darnedest to use and encourage the technique every chance I get.
Most of my coding lately has been on a legacy application which, as usual, wasn’t built with a TDD mindset. So we’ve taken the approach that, where practical, we’ll do new feature development using a TDD approach. Since a lot of the underlying frameworks that were built for this application weren’t created with unit testing in mind, there aren’t a lot of places where this is practical (mostly thanks to our database interaction, which is unfortunately tightly bound to direct SQL Client usage instead of using a repository pattern).
But I digress…
One of the patterns we use is to combine a DTO (data transfer object) with its DAO (data access object). Instances of these objects are populated from a database query or stored procedure and returned via a web service method.
So there are two elements of these classes that are testable completely in isolation:
- Are all of the object’s properties correctly decorated (using
System.Runtime.Serializationcode attributes)? And,
- Are all of the properties filled with data? We typically do this via a method we name
Fill()that takes a
System.Data.DataRowinstance as its data source. And yes, it is possible to test this method without actually touching the database (and thus turning our unit test into a potentially-brittle integration test).
Here’s a bit of the implementation code for the DTO/DAO class. I use nCrunch as my unit test runner and it’s responsible for decorating this image with the green dots, indicating that the decorated line of code is covered by one or more passing tests:
After coding for a while, writing failing tests and making them pass, things got to be quite mundane. I started to question the monotony of it all, and wondered why I was creating and modifying tests for something as “simple” as a DTO/DAO class.
Enough! It’s tested enough, right? The properties all have
[DataMember(IsRequired = true)], they’re all being populated via the
Fill method. It’s time to move on, Craig…
I then realized that I had forgotten an important property,
OperatingUnitName and added it to the DTO/DAO class. I happened to use the
Copy\Paste mechanic and so the new property got it’s
DataMember attribute “automagically”. Move on to the client code, Craig, we’ve got real work to do…
Where did this black dot come from? Oh…right…I forgot to write a test…and since I forgot to write a test I also forgot the most important part of the DAO: populating the property with a value.
Thank goodness I noticed the black dot before I went through all the trouble of running the app, seeing an empty column of OperatingUnitName values, and wondering “is it missing from the stored proc?”, “did I use the wrong field name on the grid’s column definition?”, “did someone delete all of the test data from the test database again?”.
No, it would have been none of those things. It would have been simply forgetting to add
OperatingUnitName = row.AsString(FieldNames.OperatingUnitName, true);`
Saved by the black dot! The black dot that told me that I hadn’t covered my code with tests. And the realization that this meant I had probably forgotten the really important bits.
From now on I’ll not question the value of even the most mundane unit test writing. :)