Amazon.com Widgets Getting Giddy with Dependency Injection and Delphi Spring #3 – Writing Testable Code

Getting Giddy with Dependency Injection and Delphi Spring #3 – Writing Testable Code

By Nick at June 05, 2011 22:05
Filed Under: Delphi, Software Development, Unit Testing

Okay, so in Part #2 we talked about the Law of Demeter, and how you should think about it and follow it as if it were the Word of God when building classes. 

One of the main reasons to follow the Law of Demeter is to write code and code modules that are loosely coupled.  Loosely coupled modules have minimal interactions with other modules and thus have minimal affect on those other modules.   Change something in a loosely coupled module and the chances of breaking something in another module are slim.  If you have a minimal connection to another module, then you can only cause minimal bugs in that module.

And “minimal bugs” is a phrase to warm the heart of us all, no? 

But the Law of Demeter even goes farther than that.  Using the LOD principles means that you can write “testable code”.

So I think we’d all agree that  the best way to avoid bugs in your application is to never check them in to your source control system in the first place. (And you are using a source control system, aren’t you?)  And the best way to do that is to write lots and lots of unit tests.  Unit tests are the first line of defense against bugs, as they can root out problems in your code as you write them.  They can discover trouble at the very lowest level before it becomes a system level problem.  Writing unit tests is the profound and solemn duty of every software developer.  If you do “true” test-driven development, you’ll write your test first so that the bugs never even show up at all as you write your code to make your tests pass. 

But when it comes to writing unit tests, a common refrain I hear is “I can’t test my code” or “My code is too complicated to test.”  And my response to that is this:

If your code can’t be easily unit tested, you’re doing it wrong.

In fact, this is kind of getting to be our mantra around here at Gateway Ticketing.

Now there are exceptions, of course, such as code for directly manipulating your GUI, etc. But if you are writing anything other than that -- i.e. the vast majority of the code you do write -- then you should be writing code that is testable.  But I’ll make the point again – if you can’t write unit tests for your code, then you need to change the way you are writing your code.   That is, you should be writing code that is “testable”.

Code that is “testable” has a number of familiar qualities.  The most noticeable of those is – surprise! – code that adheres to the Law of Demeter.  LOD code is easy to test because the classes you write stand alone and have limited dependencies.  Code with limited dependencies is easy to test.

A common refrain is this – “My code isn’t testable because it hooks up to too many other things like a database or a scanner or some other thing that can’t be attached to the test suite”.  And my answer to this is:  change your code to remove those dependencies and write mock objects for the instances that you can’t.

Code that is hard to test has dependencies.  Creating an instance of a given class can result in the creating of a host of other classes – even classes that you don’t know about or can’t foresee.  As noted above, heavily coupled code creates these dependencies. Consider the diagram below:

image

Here, you have a class that you want to test, but when you create it, it creates, in turn, three other classes that then  can create yet more classes, including dependencies on external devices and other systems.  Such classes are hard to test, because testing them brings in all those dependencies. 

What we need is a way to limit and even remove those dependencies in order to make a class easily testable.  And the way you do that is to find the “seam” in your class.  The seam is the point where the dependencies are “attached” to the class to be tested.  Once you find that “seam”, you can reduce and/or eliminate those dependencies.  In the diagram below, the Class Under Test is made more testable by creating classes that don’t create dependencies – a better designed class that itself uses the LOD, a “stub” class that does nothing (say, a logging class that actually doesn’t log anything) or a Mock class that merely pretends to be the external dependency without actually being the external dependency. 

image

Creating classes for which you can find this “seam” and substitute classes that don’t create the dependencies is key to creating a “testable” class.  Remember, it is hard to introduce bugs into systems that are made of up easy-to-test classes.  So, we should write easy to test classes, right?

The critical thing to remember here is that the class need not completely avoid the dependency – at some point your code is going to have to connect up and talk to that Oscillation Over-thruster – but rather your classes should be able to limit those dependencies as much as possible, and where they can’t, they should be easily able to “fake” having the dependency so the class can be tested without the real dependency.

And just how will that be done? You’ll have to tune in for the next episode!

Comments (2) -

6/6/2011 4:47:17 PM #

Kenneth Cochran

Sounds like someone has been reading Michael Feathers' Working Effectively with Legacy Code. Its the only book I'm aware of that compares source code with fabric seams. Delphi has a number of seams. In my book its a tie between objects and interfaces as to which is the most useful. Both make it trivial to create fakes, mocks and stubs. Delphi also has link seams. By pointing the linker to an alternative implementation of a source file you can essentially mock an entire unit. This can also be done with dynamic linking. I've seen a test dll substituted in for a production dll to simulate a remote connection. I imagine this can be accomplished with packages as well though I've never tried it myself. Another possible seam is Delphi's $include directive though this strikes me as a bit more cumbersome to work with than the others mentioned.

Kenneth Cochran United States |

6/8/2011 8:48:50 PM #

John Jacobson

To add to the previous comment, lately I've been trying out the idea that no class should ever be visible outside of the implementation section of the unit that contains it. External visibility should be limited to an interface for the class and a factory method. This has turned out to have a number of beneficial effects, and all because it fits the Law of Demeter in principle. You are far more loosely coupled when you publish an interface than when you publish a class (which ought to descend from TInterfacedObject for free reference-counting and deterministic garbage collection). I've been re-writing a large personal project along these lines and I have seen no performance hit from using interfaces this way.

So, as you can see, I am in total agreement about the value of the Law of Demeter to which you have been referring of late.

John Jacobson United States |

Comments are closed

A Little About Me

Hey, I'm Nick.  I'm interested in Software Development, Leadership, and Basketball.  I'm a big fan of Delphi, but love all cool programming languages.

A Pithy Quote for You

"No matter how rich you become, how famous or powerful, when you die the size of your funeral will still pretty much depend on the weather."    –  Michael Pritchard

Little Buttons and Stuff

Nick Hodges

Create Your Badge
View Nick Hodges's profile on LinkedIn
profile for Nick Hodges on Stack Exchange, a network of free, community-driven Q&A sites
Powered by DiscountASP.net
Join Dropbox

General Disclaimer

The views I express here are entirely my own and not necessarily those of any other rational person or organization.  However, I strongly recommend that you agree with pretty much everything I say because, well, I'm right.  Most of the time. Except when I'm not, in which case, you shouldn't agree with me.

Book Stuff

Earn Free Stuff

Search & Win