Test Driven Development is mystical to any engineer that doesn’t have it as part of their development culture. ?Many shops don’t have the peer pressure and leadership that requires TDD in day-to-day operations. ?Others don’t see the need when working with Legacy Codebases. ?Some engineers have never written a unit test in their professional careers. ?No matter why Test Driven Development isn’t happening; once integrated into the engineering fabric of an organization, it will quickly take hold and spur productivity.
TDD is almost like riding a bike; you really don’t know how easy it is and how much fun you can have with it until you get up and going. When the training wheels are off, Test Driven Development (TDD) becomes a brand new world full of possibilities.
I have been writing unit tests for years, out of necessity to start, but later out of the desire to lead by positive example. Having come to the Computer Sciences later than most of my colleagues, I decided early on to adopt best practices to not only ensure that I wasn’t breaking builds, but I wanted to build the respect of my colleagues. Now, I really like to make sure that everything I commit to my various development communities are well-tested and as clean as possible.
Test Driven Development practices give me the verification necessary to check code in with confidence.? ?Unit testing builds this sense of security in three different ways:
- It guarantees that what I’ve written works, whether it’s new or integrated into existing platforms and applications.
- It makes me keep my code simple. If I start writing a test and it becomes a dependency-driven, closely-coupled “implementation monster”, I can pretty much guarantee that the code is going to be the same. I’ll try to refactor this and use my tests in this manner as a guage for it’s quality.
- In large environments that have continuous-build systems, there is always the inevitable “break” that stirs up panic and finger-pointing. Code with strong test coverage rarely breaks a build. This develops a team’s confidence in an individual’s engineering skills.
So exactly HOW would I begin development by writing a test BEFORE I write any actual code, and WHY would I even want to?
We will address the “why” aspect first. “Old School” developers and my earliest mentors would create “fake” layers and tiers would test the code they were writing. A “fake layer” is defined as some type of data or code that simulates the functionality of an “expected” production-level deployment. Some development communities call these fake layers “tools” or “simulators”.
These ?fake layers? would be similar to tests, but these guys wouldn’t write tests because they never did in the past (and some still don?t!).? ?”Fake layers” can create all sorts of problems.? ?They tend to get passed around as API or Interface points, and as two different groups develop against these simulators, each makes compromises because they “must” integrate with the “tool”.? ?Testing just gives you a better framework for creating fake layers that you can create your code around.? ?It also creates a path of communication between development groups, negating the need for tools and promoting integration environments.
HOW do you start with a test?
Implementing your first Test Driven Development cycle is simple. Let?s say you will be writing an application that talks to a database that currently exists (you could even start without the database and just an ER diagram). Looking at your requirements, you are probably going to implement CRUD operations against it. You start thinking about what the interface for the Data Access Object is going to look like. ?Hmmmm? ?Let?s see? CREATE, READ, UPDATE, DELETE. So your simple Interface has four methods.
Now start with a test. Create a class called MyDAOTestImpl. MyDAOTestImpl will test the ?Implementation Class for the interface?s methods. When we create a method in the test that tests well, we then create the interface method, then the move the test method, with proper modifications, into the a new ?MyDAOImpl class. It makes you create very smart tests that ensure you are ?CRUD-ing? the data you expect. Coding in this way also creates the implementation to your interface at the simultaneously with the test. Finally, it makes you think about the interface and the implementation, and affects your overall design in a very positive light.
Now let?s take it further. You?ve created all the methods in your Impl class and your Interface methods can be extracted and the actual interface is now written and, for the time being, complete. Now let?s write a test that ?calls the Interface and implements a ?new Implementation Class through it. You can now see how clean your Interface is? –? how easy are your methods to use, how are things being cleaned up, and finally, how are exceptions being caught? Are you satisfied with the results so far? If so, proceed to the next layer!
The next layer may possibly involve a creating a Session Facade to allow for user interaction with the database (more complex implementations would have deeper structures). You may create an Object model that translates the Database relationships into some type of presentation-level object gouping, and write tests to reflect this. It becomes very obvious what objects you need when you start writing a test that outputs expected data a conditioned manner.
Your first cut at it may look like horrible code; it may be some type of monolithic monster, but it will give you clarity to understand how things must be split up. You keep refactoring and writing tests, and sooner rather than later, you are suprisingly code-complete, tight and ready for QA!
Do what works for you.
Even after all this I?m sure that some engineers are completely poo-pooing this way of developing applications. Many say that it’s writing “extra code”.? ?I dispute this.? ?Before writing so many tests, I wrote quite a bit of code and refactored it before it was checked in.? ?Sometimes I’d get caught up in a particularly cruel block of logic that would take hours to get to the bottom of, or worse I’d break somebody else’s logic block in another part of the application and it wouldn’t be found for a few days.? ?This was the worst case.? ?A set of unit tests would have found it in seconds, and it would take minutes to fix.? ?Concurrently, a set of tests to track the expected output of a logic block would have ensured that anything I’m stuck on can be worked through quickly.
Still not convinced?? ?That?s fine if it works for you.? ?TDD works for me.? ? I?ve found that as my tested code base and coverage build up, my productivity jumps dramatically as the project continues because I write less and less code as the project nears completion.
Test Driven Development is all about making everything solid. Using TDD, you?ll be writing one line of code to your previous ten, and when your ?business guy? walks in and asks for a change, you?ll be going home at 5 instead of having your car languish in the parking lot after midnight. You?ll also have more confidence in the quality of your check-ins and builds, and when things go wrong and the inevitable finger-pointing starts, you won?t be a pointee!