CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Jeremy D. Miller -- The Shade Tree Developer

Under the hood and working with .Net, TDD, Software Design, and Agile Stuff

Designing for Testability

EDIT:  What I should really say is that it isnt' just Designing for Testability, it's Designing with Testability 

From a question on my Passive View blog post

 "should we design for testability, or should we try and test what's designed (perhaps designed badly, so we refactor later)?"

Here's my take:

"Done, done, done" isn't just writing code.  It's writing code and verifying that that code works correctly.  You don't ship until the code is proven to work (hopefully).  Designing for testability might cost you extra time in coding (which I would actually dispute somewhat), but can easily save time in the whole by cutting down on the time spent debugging and testing.  I see testability design as a way to optimize the time to deliver, even if it ups the time spent on design or coding.

One of the very painful truths that TDD newbies learn the hard way (myself included) is that retrofitting automated tests to existing code can be very difficult.  Just trying to test what's designed may not work out very well, and frankly, I have yet to see a codebase that wasn't built with TDD that was easy to test.

What is Testability design anyway?  Granted, there are some things I do like opening up more public accessors or pulling out more interfaces strictly for testing that could arguably described as "bad."  However, most of what constitutes designing for testability, or using testability as a design heuristic, is a matter of how best to assign responsibilities by following older design principles that predate TDD by many years.  Achieving testability is mostly a matter of separation of concerns, coupling between classes and subsystems, and cohesion.  Exactly the design qualities that we've always strived for to make our code maintainable.  It's what we've been trying to do anyway.  If you practice traditionally good design, you might already be there to testability. 

Testability is, in my opinion, the ultimate design smell detector at the granular level.  If you're finding it hard to unit test your code, you've likely got a coupling or cohesion problem.  Testability is yet one more design tool to stick in your design toolbox right between UML/CRC modeling and code smells.  At least think of it this way, driving an application design at least partially through tests is yet another example of starting with the end in mind.  How will I know that this code works correctly?  How will I know that I'm done?

Yes, using TypeMock or switching to a dynamic typed language will let you more readily create testing seams with less conscious effort, but that's not the entire ballgame.  Throw testability and orthogonality out the window to write a ball of mud and no amount of TypeMock magic is going to help you out.

 

Anyway, go ahead and start arguing with me.  As always, comments are open.



Comments

Colin Kershaw said:

"I have yet to see a codebase that wasn't built with TDD that was easy to test."

+1

My experience has been that mocking frameworks are often used to test "untestable" designs - treating symptoms rather than the cause (tightly coupled, loosely cohesive code).

Another great post - keep 'em coming.

# June 29, 2007 12:48 PM

Sam Gentile said:

TGIF!! I am super busy right now designing a multi-CPU/multi-threaded Parallel Calculation Engine and

# June 29, 2007 1:15 PM

Gil Zilberfeld said:

Right on!

I was actually discussing this with a colleague yesterday. She's starting with automated testing (not even TDD), and she's trying to put tests around the existing code.

It is hard. We need to unlearn the "produce code cause it's faster" for the things we learned in the university.

Sorry, but you won't get arguments from me.

# June 29, 2007 2:30 PM

ulu said:

@Jeremy,

No, I won't argue with you. I completely agree.

Perhaps I didn't make myself clear. I didn't mean testing the existing code. By "testing what's designed" I meant "first design, diagrams and stuff, then write tests, then write code". I was thinking that we shouldn't design just for the sake of testability. But when testability is used as a criterion for a good design, yes, I'm all for it.

However, I'd rather treat testability as an advice, not as an absolute rule, and I don't like being forced by testability, even when it enforces something good ;)

Frankly, you got me converted to the view-presenter separation idea, I'm coding my first presenter now (or is it a supervising controller? i'm still learning these terms), and I feel much better about it. Still avoid these interfaces and dependency injections, my tools let me test everything without them, and I don't see any god they could make me in my case. Perhaps on the next project..

# June 30, 2007 5:40 PM

The Disco Blog » Blog Archive » The weekly bag– June 29 said:

Pingback from  The Disco Blog  » Blog Archive   » The weekly bag– June 29

# July 1, 2007 9:23 PM

Designing for Testability « Tuff Stuff said:

Pingback from  Designing for Testability « Tuff Stuff

# July 4, 2007 4:39 AM

carnival of the agilists, 5-jul-07 « silk and spinach said:

Pingback from  carnival of the agilists, 5-jul-07 « silk and spinach

# July 5, 2007 3:32 AM

ulu said:

Hi Jeremy,

I need an advice on TDD, and I thought I could ask my question here.

Suppose I want to implement a ComplexOperation method of my Controller class. Being converted to TDD recently, I break this into three smaller steps, and then write a test for it, mocking the calls corresponding to these steps. I end up with a test containing just 3 expectations and no asserts. Now, I write my ComplexOperation method with calls to these 3 steps, I've got a green, and I'm happy.

A couple of things look wrong here. First, my test doesn't help me to find mistakes with my code. If I forget a step, it will show both in my test and in my code. So, the test is not really testing anything. Second, if I choose to change my design, I'll have to change the test as well. There's no "refactor" step in the test-code-refactor trio.

The problem is that my test duplicates my code. It doesn't test the result, it tests the process. I don't see any way to include any assertions in this test, since it would involve implementation of my three steps. The question is, do I really need a test here? Or should I change my design?

Thanks a lot for your advice.

# July 11, 2007 12:41 PM

Jeremy D. Miller said:

@ulu,

I'll try to shoot you an answer in the morning

Jeremy

# July 11, 2007 10:08 PM

Jeremy D. Miller -- The Shade Tree Developer said:

About a year ago I hit a patch where I wasn't able to blog much (something about finding a new job

# October 18, 2007 9:20 AM

design for testability said:

Pingback from  design for testability

# July 4, 2008 2:44 PM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add

About Jeremy D. Miller

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 previously worked as a systems architect building mission critical supply chain software for a Fortune 100 company and learned agile development practices as a .Net consultant at ThoughtWorks, one of the pioneers of agile development. Jeremy is the author of the open source StructureMap (http://structuremap.sourceforge.net) tool for Dependency Injection with .Net and the forthcoming StoryTeller (http://storyteller.tigris.org) tool for supercharged FIT testing in .Net. Jeremy's thoughts on just about everything software related can be found on his weblog "The Shade Tree Developer" at http://codebetter.com/blogs/jeremy.miller, part of the popular CodeBetter site. Jeremy is a Microsoft MVP for C#. Check out Devlicio.us!

Our Sponsors

Free Tech Publications

This Blog

Syndication

News

All opinions expressed here constitute my (Jeremy D. Miller's) personal opinion, and do not necessarily represent the opinion of any other organization or person, including (but not limited to) my fellow employees, my employer, its clients or their agents.

About Me

"Best Of" Compendium

StructureMap (Dependency Injection for .Net)

StoryTeller (Supercharged Fit)

Build your own Cab

TestDriven

MVP