Last month I had the honor of speaking at the Orlando .NET User Group (ONETUG) in Orlando Florida. My talk, entitled TDD: A Pragmatic Approach seemed to be of interest to everyone in attendance. Lots of questions and interest around Test Driven Development. After the presentation we continued the discussions at a local watering hole with drinks and appetizers. This group really knows how to make a speaker feel welcome!
So what is a Pragmatic Approach to TDD? Well, first let’s define Test Driven Development from Wikipedia:
Test-driven development (TDD) is a software development process that relies on the repetition of a very short development cycle: requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that isn’t proven to meet requirements.
Kent Beck, the man credited for popularizing TDD has this to say:
Clean code that works – now. This is the seeming contradiction that lies behind much of the pain of programming. Test Driven Development replies to this contradiction with a paradox – test the program before you write it.
That’s all well and good, but what about a pragmatic approach?
When I was first introduced to TDD it was on a team that all agreed to adopt the practice together. We learned together. We struggled together. We each wanted to rip our hair out at times. In the end, the team persevered and the end product, and our own skills benefited.
I’ve since transitioned to a number of different teams where I introduced TDD with varying degrees of success. I find I have the most success when I convey the benefits of TDD to an audience open and willing to listen. Unfortunately, this isn’t always the case. There are some developers that have not had a pleasant experience with those preaching the rewards of TDD. Some have been too dogmatic in their approach and turned off the prospective developers altogether.
Recognizing this, my own approach is more pragmatic. For this reason, and because I am still learning and honing my technique, I find being a little more loose and a little more practical in my approach to be greatly beneficial and increase the chances of adoption by my team.
For our purposes let’s look at the code example that accompanies my talk: https://github.com/ovation22/PragmaticTDD.
This example started life as a simple MVC application. The Web.Tests project uses moq mocking framework. There shouldn’t be any business logic in your web application, so we’re just testing that services were called from our controllers.
Dependency Injection is handled by Autofac and is wholly untested. Simply running the website will show that this is wired up correctly, or not. At some point, in a production application I would likely look into some type of Integration Test project, but we’re simply not there yet.
The Services project is where all of the business logic lives. The Services.Tests project tests each and every public method for our services. Where an IRepository is needed, a FakeRepository backed by a FakeDataContext is substituted. A little setup for each test scenario is all that is required. This helps to keep things simple and ensure that we’re testing the smallest possible unit.
The TimeManager in the Common project has it’s single test. The two methods in the generic Repository have their tests as well. The Data Transfer Objects and the Models are tested through their usage in the Services and Web tests. The Entity Framework bits are untested, though most the details are abstracted away by the generic Repository.
My approach is somewhat casual. I try my best to write good tests up front. I recognize that some things are difficult to test. When I have to interface with 3rd party code I’ll implement a layer of abstraction so that I’m only testing how my code interacts with the 3rd party code.
I want to focus my time on writing highly performant, well tested and testable, maintainable code. I don’t want to get into a religious war with anyone, and I don’t want to turn off anyone to the benefits of TDD.
Please do take the time to explore the code on github. Complete the homework and add your own bits.
If you’re interested in the accompanying slides from my talk, you can see them below: