It's quite possibly the biggest buzzword for software developers right now. Test driven development (TDD) is being tested and employed in several places in the software engineering field. Last summer, the company that I was interning for was using it for at least one project. Due to the amazing success of that particular project, I am sure that they have since increased the presence of TDD in their company.

TDD is awesome

Unfortunately, I was not a member of the TDD team. Instead, I was on a team that was practicing more traditional methods of designing features, developing those features and "Big Bang" testing those particular features at the end of the development process. We delivered the product on time, but I feel that the delivery was at the cost of significant quality. Instead, I felt that something needed to be different.

One of my friends was on the TDD project; He told me how successful it was and how it works. He mentioned some really cool aspects of TDD that really peaked my interest. TDD, he said, helped improve the quality of the code that the developer wrote. It did this in two different ways: it forced developers to write the expected inputs and outputs†of the methods she was writing and it gives nearly instantaneous feedback to the developer aboutbugs and unexpected behavior. Many bugs are introduced into software because developers misunderstand the expectations. And, the instantaneous feedback allows for the developer to quickly find and fix bugs that may otherwise take precious time for quality assurance teams to investigate.

TDD in action

I was notably excited about the prospect of TDD. I came back to school last fall with high hopes for this emerging method of developing and writing software. I got my chance to put it into action when I was assigned the task to develop a web-based Apples to Apples Online application. I convinced my partner (Kyle Rhodes) to use Ruby and Ruby on Rails as the development language and framework, respectively. Rails has aspects that make TDD very easy. It has a built-in automated testing harness that you just drop simple, easy-to-write tests in. Following this grain, several plug-ins have been developed for Rails (and Ruby) that make testing easy and even fun (e.g. flexmock). Kyle and I were chugging away, using TDD to develop the application and were moving along smoothly.

At least, everything was smooth until the part where we needed to work on the views. The program was that we worked on our features horizontally. This, I know now, is a big no-no in Rails (and MVC in general) development. Our database worked just fine; we tested that. Our application logic was solid; we tested that. The connection between the data layer and the application layer was smooth and logical; we tested that. Everything was supposed to work because we tested†it. However, as solid as our application logic was and data layer was, we did it wrong. We didn't realize this until the final part of the feature set we were developing needed to be implemented.

My confidence in TDD was shattered. My first attempt at using the development practice was a complete failure, in terms of the project outcome. Luckily, though, I was able to learn a lot out of the experience. TDD itself is a wonderful practice on the functional level. However, TDD cannot ensure that features are correctly being implemented nor can it guarantee user satisfaction. But, at this level, every thing would still need to be big-bang tested at the end of the project.

Two new practices: ATDD and BTDD

I found out about two new practices that attempt to address the problems that I found with TDD during my own experience.

Acceptance Test Driven Development takes the standard reverse pyramid method of testing and blends it with TDD. This means that, after feature prioritization, each feature is implemented incrementally. To start, the acceptance tests for each feature are written. These are broad tests that are usually based on the user stories for that particular feature. Then, the developer writes the integration tests that describe the interaction between modules, classes, etc. Finally, the developer writes the unit tests one at a time, satisfying each unit test exactly as a developer would in TDD. The TDD cycle repeats until each integration test is satisfied (solving each test sequentially). When all of the integration tests pass, all of the acceptance tests should pass. If not, then additional integration tests need to be written and we recycle until the acceptance tests pass. At this point, the feature can be considered "finished" in development terms. The acceptance, integration and unit tests will be rolled into the regression test suite (if not automatically done so).†

Behavior test driven development (BTDD) is similar to ATDD, except that it uses†the business rules (what would become user stories) of the program to test the system. This abstracts the acceptance testing material to a medium that both developers and customers can understand. The BTDD tests replace the acceptance tests and the process continues the same as ATDD does. RSpec, Rails' BTDD plug-in, has wonderful examples of BTDD on its website.

While I haven't used these methods for development, I feel excited for the promise that they bring. They eliminate both "Big Bang" testing at the end of a project and a loss of feature-focus brought on by simply writing unit tests and satisfying them over and over. There are many proponents of TDD as well as critics, but either way I think that every developer should investigate TDD in some fashion.