For many people (myself included), Test Driven Development is far from instinctive.  It even takes some inward reflection to learn how you, as a programmer, design and architect while coding.  The very first question I had was “How do I drive development with tests?”  In some ways this is a can of worms.  Deeper and deeper you’ll tumble down the rabbit hole, because TDD is exciting. Let’s start with the step-by-step recipe for TDD:

  1. Write a test that fails.
  2. Write code to make the test pass.
  3. Refactor ruthlessly to simplify.
  4. Rinse, repeat.

That is a breakdown of the mechanical process.  Knowing it is only the first step.  With this in mind, I would like to share my opinions and observations of this design method.

Unit tests can read like low level specifications.  A practical example is that someone jots down some pseudo code and asks you to write a class based on how they would use it.  Fundamentally, TDD is taking that idea and going pro.

Writing tests as simple examples is a great starting point for high quality design.  Focus on showing how simple it is to set up an object.  I have noticed that writing tests first influences me to write shorter methods, as well as simpler classes.  Small chunks are easier to understand, and TDD can definitely help you stay on that track.

Some other side effects of writing the tests up front is that you end up with a suite of tests at the end of the process, resulting code is more extensible , easier to maintain, and it is a way to gain instant gratification.  It is somewhat thrilling (okay, maybe that’s just me…) to see a test compile and run.

All of these things are great, but let us remember that TDD is design.  Tests are a great part of the process, but it’s something we are borrowing as the means to achieving design goals.  By nature, test driven development lends itself to the SOLID principles.

TDD especially lends itself to the “Single Responsibility” principle.  Singleton objects tend to be easier to test, and help create clear dependencies.

”If you start with simplicity, and expectations and demands for simplicity, you’re going to end up with higher quality design.” - Scott Hanselman

The overall process of TDD helps to detect code smell, or any symptom in the source code that indicates something may be wrong.  As a rule of thumb, if you don’t enjoy setting up the test, something can probably be improved.  This is referred to as “Test Friction.”  There should be a threshold of discomfort when setting up complicated tests.

Another TDD warning flag is solubility—how hard is it to understand code?

“How much effort do you have to make before you can learn what an object does?” – Scott Bellware

Code smell is an excellent indicator that code needs to be refactored.  Having the suite of unit tests that you (presumably) wrote before (or at least while) coding will be the safety net for refactoring.  Refactoring is successful if tests pass.

References:

Hanselminutes, Episode #31- Scott Hanselman discusses TDD with Carl Franklin
Hanselminutes, Episode #146 – Scott Hanselman discusses “Test Driven Development is Design” with Scott Bellware

Wednesday, July 08, 2009 10:21:30 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [1] -
Code Smell | Hanselminutes | Refactoring | Scott Hanselman | TDD | Testability | Unit Testing

I have often asked myself "How should I write this test?"  It's hard, frustrating, and takes a lot of devotion.  The best answer I can come up with is usually "just dive in."

Getting a clear definition of what a unit test is supposed to do is a good start.  The pattern I notice while writing unit tests is that you must set up any required dependencies, perform a task, and then assert that some result of business logic.  If the expected result is the actual result, the test can be passed.

There are varying degrees of how a test can pass and it’s really up to you. I tend to feel that getting the test to compile and run a basic scenario is the tip of the iceberg. The more ground my tests cover, the more satisfied I am that I won’t run into unpredictable situations. So, for me, a good unit test is one that leaves almost no uncertainties.

As a common practice, I try to output as much useful information as I can about the tests that I write.  If I am testing the creation of an object with parameters, I will output what the parameters are (perhaps I'm trying to test many iterations of parameters).  After I create the object, I assert that it is in a good state, and if it is not, I fail the test and output any reasons I can find.  Enclosing the tests in a try/catch block is helpful to catch exceptions I wasn't prepared to encounter.  Writing out the exception message and stack trace during the test helps to see what might have gone wrong in the test without having to spend as much time debugging.  Even if a test passes, I make it a habit of outputting the results of the passed test.  The simple truth is that tests are fallible.

Testability is a word we often use to describe the practicality of properly testing.  The term should infer that code is easy to test. Just because something was tested, doesn’t mean that it was done easily or done well.  Code that is easy to test tends to require minimal setup, and accomplish a minimal number of goals.

I would be lying if I said that unit tests didn't make an ounce of difference in my code.  While the benefits are not as obvious up front, they become more apparent over time.  In my opinion, it is one of the best skills for a developer to learn.  Writing good unit tests takes practice, so keep trying (I know I will be).

Wednesday, June 17, 2009 2:11:00 AM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] -
Testability | Unit Testing

John Nelson

mugshot I am a passionate C# Developer working in ASP.NET on an e-commerce solution for ticketing software. I work across all of the application layers, including server side functionality, and client side programming with jQuery and MS Ajax. Although my full time job is in WebForms, I spend many of my off hours working with MVC. I am especially interested in productivity and good programming practices.

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2010
johncoder.com
Statistics
Total Posts: 39
This Year: 15
This Month: 0
This Week: 0
Comments: 4