Succeed with TDD by designing with TDD

After 2 years of using Test Driven Development on .NET projects I’m a believer. Effective TDD leads to cleaner code, fewer bugs, and superior architectural qualities. Systems written with TDD are easier and safer to modify and deploy, leading to a reduced cost of ownership over the lifetime of an application. Yes, TDD means a lot more code to write. Yes, TDD can make the activity of writing code take longer, but it can and does shorten the time to delivery of working, production-quality code.


Using TDD dramatically changed the way I approach OO coding for the better, but I made a lot of mistakes along the way. The easiest way to learn TDD is to work closely with teammates that are already comfortable with TDD. Otherwise, you are on your own, and a lot of the writing I have seen on TDD falls into one of two categories — “TDD is Cool” and “How to use NUnit.” You’ve got to start somewhere, but when faced with the very real world of enterprise architecture (databases, messaging, user interfaces, Active Directory), the simple examples of create an object, pump in some inputs, and validate the results suddenly don’t seem to be enough.


In my experience, newcomers to TDD often struggle with the mechanical work of writing unit tests, negating most of the value of TDD by writing unit tests that are too coarse. A common complaint is that the tests are too hard to write, or just take too much time to write. Frequently, well-meaning developers will “just make it work” first, and retrofit tests around the new code later. I did this pretty often on my first TDD project — with the result largely being a set of fragile tests that flat out sucked and broke the build anytime someone breathed too hard on the codebase.


The usual culprit is the way that the code is written and structured — god and blob classes, stovepipe architecture, poor separation of concerns, and an overuse of static methods. So how do we write code to maximize the efficacy of TDD? The most important thing is to write good OO code (I’m not trying to exclude folks doing procedural or functional coding, but this post is meant primarily for .NET developers). A couple years most of my team of System Architects (sic) were sent to an introductory(!) class on OOA/D and came back giggling and blathering about code being “Highly Cohesive” and “Loosely Coupled.” All those fuzzy sounding OO qualities we’ve known about for years aren’t just a way to impress other developers while stroking your beard, they are absolutely necessary to easily utilize TDD. It’s time to take these concepts seriously in the .NET world. Read this from Scott Bellware on TDD in the Microsoft community versus the Java world. A bit more on cohesion and coupling later.


Which Comes First, Chicken or Egg?


A TDD developer follows a continuous cycle of writing a small, isolated unit test for a little bit of functionality, then writing a little code to make the test pass. Ideally, an individual unit test involves a discrete chunk of a single class (or a few classes). How do you know if your unit tests are small/isolated/discrete enough? Easy, VS.NET debugger sessions become uncommon and short and test failures are easily diagnosed and remedied.


So if small unit tests are good, how do you design your code to maximize the TDD goodness? By designing with TDD in the first place.


Using TDD as a Heuristic


From Merriam Webster – Heuristic: “involving or serving as an aid to learning, discovery, or problem-solving by experimental and especially trial-and-error methods ” Simply put, TDD is a technique for determining class structure by making testability a first class consideration in your design. Focusing on testing a unit of code at a time leads to creating cohesive classes with a distinct purpose and responsibility. The need and desire to quickly setup an isolated unit test on a class will lead to a loosely coupled design. Here’s a couple of quick questions answer to test whether your class structure really exhibits desirable architectural qualities:



  1. Paraphrasing Michael Feathers, can someone fire up VS.NET on your code, take any arbitrary method, and write a unit test in a short amount of time?
  2. Can you completely remove your computer from the network and run 100% of your unit tests covering both user interface and business logic code? Using a local database instance or a wireless connection does not count.
  3. Can you write tests that only involve one or a very few classes?
  4. If you are writing a web application (or a Web Service for that matter), can you run unit tests on much of your user interface code with IIS turned off?

Test Driven Development is an Alternative Design Process


There is far more to TDD than automated unit testing. Much like UML modeling or CRC cards, Test Driven Development is a process to explore a design and arrive at a good solution. The difference, in my mind, is that TDD is a “bottom up” process, where other design techniques are “top down.” The truly good practitioners focus on rapidly building discrete, working pieces of code, then arranging the coded classes into an emerging structure guided by a knowledge of good design principles and a strong working understanding of Design Patterns.


Some of the impetus for using UML or CRC is the belief that it easier to explore design ideas by using abstract non-code artifacts because code itself is too difficult or inefficient to change once it is written. TDD can turn this assumption on its head by making code easier to change and restructure because the resulting code is cohesive, and safer to change because a good automated unit test suite can catch errors resulting from the changes. A good refactoring and code navigation tool like ReSharper (JetBrains rocks!) makes this type of malleable code assembly more efficient.


One way to think about TDD is an analogy to Lego blocks. The Lego sets I had as a child were the very basic block shapes. Using a lot of little Lego pieces, you can build almost anything your imagination can create. If you buy a fancy Lego set that has a single large piece shaped like a pirate’s ship, all you can make is a variation of a pirate ship. Over the next month or so, I’m going to blog a TDD Starter Kit of design concepts and strategies. Keep watching this space, the next posts will be shorter and actually contain code.

About Jeremy Miller

Jeremy is the Chief Software Architect at Dovetail Software, the coolest ISV in Austin. Jeremy began his IT career writing "Shadow IT" applications to automate his engineering documentation, then wandered into software development because it looked like more fun. Jeremy is the author of the open source StructureMap tool for Dependency Injection with .Net, StoryTeller for supercharged acceptance testing in .Net, and one of the principal developers behind FubuMVC. Jeremy's thoughts on all things software can be found at The Shade Tree Developer at http://codebetter.com/jeremymiller.
This entry was posted in Test Driven Development. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://codebetter.com/members/kkkk9/default.aspx kkkk9

    After working on an agile team with tdd, ORM, design patterns, I’m a believer of the methodologies too until recently when I moved from Montreal to Toronto. I have serious problem finding a job in Toronto with my skill set. Not many companies have projects using TDD, ORM, dependency injections…Companies prefer someone who have solid experience using javascript than someone with TDD experience. Very depressing. I was asked question like what’s the difference is padding and margin, what’s the difference if value type and reference type, what namespace to include when calling a web service for senior dev jobs:( Don’t know when I can find employment again.

  • http://codebetter.com/members/kkkk9/default.aspx kkkk9

    After working on an agile team with tdd, ORM, design patterns, I’m a believer of the methodologies too until recently when I moved from Montreal to Toronto. I have serious problem finding a job in Toronto with my skill set. Not many companies have projects using TDD, ORM, dependency injections…Companies prefer someone who have solid experience using javascript than someone with TDD experience. Very depressing. I was asked question like what’s the difference is padding and margin, what’s the difference if value type and reference type, what namespace to include when calling a web service for senior dev jobs:( Don’t know when I can find employment again.

  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    @Troy,

    First, this post is ancient. Top-Down vs Bottom-Up might not be a useful argument at all in regards to TDD because I’ll do either depending upon the situation. With TDD you start with whatever task you *do* know how to do and build and test that first. I often design the interface in the middle of writing a unit test for the client that’s going to consume that interface. It’s not necessarily prefactored other than starting with the idea that certain responsibilities are fulfilled by different classes. Like I’ll write a Presenter class that interacts with a View and maybe a Repository. I might develop the Presenter before the other pieces and generate the View and Repository interfaces in the course of writing the Presenter. You can call that top down if you want.

    Other times, I might know how to do one granular operation of a much larger algorithm, but not the whole. I’ll build some of the individual steps using TDD in isolated pieces, and let the whole of the algorithm code emerge from the structure that is suggested by the little pieces. That I would call bottom up.

    More here: http://codebetter.com/blogs/jeremy.miller/archive/2006/05/30/145752.aspx

  • http://blog.troyd.net/Test+Supported+Development+TSD+Is+NOT+Test+Driven+Development+TDD.aspx Troy DeMonbreun

    I would consider TDD as a heavily Top-Down process, given that your tests depend on some sort of mocking/stubbing of dependencies that often don’t exist yet, and in the sense the TDD community seems to heavily support DI as part of TDD (i.e.: DIP is top-down — http://en.wikipedia.org/wiki/Dependency_inversion_principle). Also, most TDD practioners, when explaining TDD, give Top-Down examples.

    Could you elaborate on how you feel TDD is Bottom-Up?

  • jmiller

    Jeffrey, it might be an unpleasant experience, but I *know* that it is possible to create an HttpContext and make it current in a unit test. I’ve seen it done, I just didn’t go look much at how they did it. You’ll have to fire up Reflector to pull it off I’d imagine.

    Let’s talk about it at the Agile lunch today. I’m coming up on my first ASP.NET development in 2 years pretty soon.

  • http://www.jeffreypalermo.com Jeffrey Palermo

    Great post! TDD is very straight-forward with class libraries, but I’m having a hard time right now because I’m writing web controls. I need to be able to test my web control in an HttpContext without running an entire web page.