Jeremy D. Miller -- The Shade Tree Developer

Sponsors

The Lounge

Syndication

News

Advertisement

Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
TDD Design Starter Kit - Dependency Inversion Principle
In the last episode of the TDD Design Starter Kit, I talked about the need to build cohesive classes, and make the relationships between classes loosely coupled. The specific benefit for TDD is to truly isolate the functionality of a class under the microscope of a unit test. But we've done all we can to isolate our classes, and we still have some interaction with dependencies. How then can we test the class in isolation?

Use the Dependency Inversion Principle (DIP) to isolate one class from the actual implementation of its dependencies.

Depend upon Abstractions. Do not depend upon concretions

DIP is certainly not an invention of TDD practitioners, but it is employed frequently for no other reason than to enhance testability.

Take a look at this code that does not employ the Dependency Inversion Principle.


public class MessageProcessor1
{
public void RouteOrder(Order order)
{
string queueName;
if (order.IsComplete)
{
queueName = "Queue.Completed";
order.CompletionDate = DateTime.Now;
}
else
{
queueName = "Queue.Incomplete";
this.assignOrder(order);
}

OrderQueue orderQueue = new OrderQueue();
orderQueue.SendOrder(order, queueName);
}

public void assignOrder(Order order)
{
// do something to the order
}
}

public class OrderQueue
{
public void SendOrder(Order order, string queueName)
{
MessageQueue queu = new MessageQueue(queueName);
queu.Send(order);
}
}


So what's so wrong? The MessageProcessor1 class cannot be tested, or function, without the OrderQueue class being executed.

Not only is MessageProcessor1 strongly coupled to OrderQueue, it is coupled to anything that OrderQueu is dependent on. In this case the MessageProcessor1.RouteOrder() method cannot be tested unless MSMQ is available. More annoyingly, any automated test would need to query MSMQ to get the resulting Order object to compare the expected results.

Now, using DIP we make the MessageProcessor2 class dependent upon an abstracted IOrderRouter interface instead.




public interface IOrderRouter
{
void SendCompletedOrder(Order order);
void SendIncompleteOrder(Order order);
}

public class MessageProcessor2
{
private readonly IOrderRouter _router;

public MessageProcessor2(IOrderRouter router)
{
_router = router;
}

public void RouteOrder(Order order)
{
if (order.IsComplete)
{
order.CompletionDate = DateTime.Now;
_router.SendCompletedOrder(order);
}
else
{
this.assignOrder(order);
_router.SendIncompleteOrder(order);
}
}

public void assignOrder(Order order)
{
// do something to the order
}
}



MessageProcessor2 is only dependent upon an interface, and can use any implementation of the IOrderRouter interface (in theory).

Here's what a unit test for MessageProcessor2 might look like:


[Test]
public void RouteACompletedOrder()
{
Order order = new Order();
order.IsComplete = false;

DynamicMock routerMock = new DynamicMock(typeof(IOrderRouter));

// SendIncompleteOrder(Order) should be called on the incomplete order
routerMock.Expect("SendIncompleteOrder", order);
routerMock.ExpectNoCall("SendCompletedOrder", typeof(Order));

IOrderRouter router = (IOrderRouter) routerMock.MockInstance;

MessageProcessor2 processor = new MessageProcessor2(router);
processor.RouteOrder(order);

// Call to the DynamicMock to verify the interaction
routerMock.Verify();
}


Now we have our routing logic decoupled from the delivery mechanism. Besides testability, we have added the ability to substitute other delivery mechanisms like a web service, MQ Series, or simply writing to a file.

Mechanically, there is a couple things of note in the unit test above. I used a dynamic mock object with NMock as a stand-in for the IOrderRouter interface to test the interaction. The IOrderRouter instance was passed into the MessageProcessor2 constructor, not created by MessageProcessor2 itself. This is an example of Dependency Injection (Inversion of Control). I will try to blog on both topics soon.

Rules of Thumb to Use DIP

  1. Anytime your code calls out of the CLR, and maybe just the current AppDomain itself. I would isolate any kind of call to databases, messaging queues, web services, and remoting behind a .NET interface. In ASP.NET or web service applications, always abstract any kind of call to the HttpContext objects. Nothing gets in the way of automated testing like coupling to the ASP.NET runtime. Remember, one of your unofficial design goals is to test as much of the application as possible with your laptop disconnected from the network. Look at the Gateway pattern. As a mild rant, using a Service Oriented Architecture does not guarantee that your actual code is loosely coupled. I'll expand on that soon.
  2. Singleton's. Singletons can throw a pretty serious monkey wrench in your unit tests by maintaining state between unit tests. Here is one way to avoid the Singleton issue I stole from some former colleagues that wrote PicoContainer.
  3. Interface points between major subsystems. Aggressively use the GoF Facade pattern to limit the exposure between subsystems, and abstract the interface to allow for easier testing with mocks or stubs.
  4. Extension points. This is a pretty obvious usage, but knowing when to make an abstracted extension point is way, way beyond the scope of a mere blog post.

A great codebase to look at for examples is the CruiseControl.NET application. I think they do a very good job at testing a nasty piece of functionality.


Posted Wed, Jul 20 2005 5:00 PM by Jeremy D. Miller
Filed under:

[Advertisement]

Comments

Jeremy D. Miller -- The Shade Tree Developer wrote TDD Design Starter Kit
on Thu, Jul 21 2005 1:05 PM
Here's a handful of articles on designing with or for TDD I had originally posted on my...
Jeremy D. Miller -- The Shade Tree Developer wrote Inversion of Control with the Plugin Pattern
on Tue, Sep 13 2005 12:24 AM
Inversion of Control (IoC) is an old principle in object oriented programming, but it’s gotten a lot...
Jeremy D. Miller -- The Shade Tree Developer wrote Inversion of Control with the Plugin Pattern
on Mon, Oct 3 2005 10:06 AM

(IoC) is an old principle in object oriented programming, but it’s
gotten a lot of buzz the last couple...
Jeremy D. Miller -- The Shade Tree Developer wrote Inversion of Control with the Plugin Pattern
on Mon, Oct 3 2005 10:10 AM
(IoC) is an old principle in object oriented programming, but it’s
gotten a lot of buzz the last couple...
Jeremy D. Miller -- The Shade Tree Developer wrote The Dependency Injection Pattern – What is it and why do I care?
on Thu, Oct 6 2005 11:58 AM
A couple of weeks ago I wrote about using the Inversion of Control (IoC) principle to create classes...
Jeremy D. Miller -- The Shade Tree Developer wrote Test Driven Development with ASP.Net and the Model View Presenter Pattern
on Wed, Feb 1 2006 11:18 PM
A friend of mine was asking me a while back about ways to apply the Model View Presenter (the “Humble...
Jeremy D. Miller -- The Shade Tree Developer wrote Test Driven Development with ASP.Net and the Model View Presenter Pattern
on Thu, Feb 2 2006 7:11 PM
Author: <a href="blogs/jeremy.miller/">Jeremy D. Miller</a><br />A friend of mine was asking me a while back about ways to apply the Model View Presenter (the “Humble Dialog Box”) pattern to ASP.Net development to promote easier unit testing of the user interface layer. Two weeks and a major case of writer’s block later, I finally finished the post. I wrote a blog post last spring describing the usage of MVP (“The Humble Dialog Box”) with WinForms clients, but web development in general and ASP.Net in specific comes with a different set of challenges.
Jeremy D. Miller -- The Shade Tree Developer wrote Achieve Better Results by following Jeremy's Third Law of TDD: Test Small Before Testing Big
on Tue, May 30 2006 2:43 PM
Getting back on track with TDD content.  One of the most important lessons learned the software...
JayFlowers > Unit Testing and TDD Resources wrote JayFlowers > Unit Testing and TDD Resources
on Tue, Jun 27 2006 9:46 PM
Jeremy D. Miller -- The Shade Tree Developer wrote Best of the Shade Tree Developer (with actual links!)
on Mon, Aug 7 2006 4:51 PM
Between being extremely short handed at work, tech' reviewing a new book, a
possible book proposal...
Jeremy D. Miller -- The Shade Tree Developer wrote Some Concepts to Know First
on Sun, Jun 29 2008 4:40 PM

  JEREMY’s NOTE:  I’m trying to rewrite the StructureMap documentation today, and I’m going

Community Blogs wrote Before you use an IoC tool, some concepts to know first
on Sun, Jun 29 2008 5:03 PM

JEREMY’s NOTE: I’m trying to rewrite the StructureMap documentation today, and I’m going to blog most

DotNetKicks.com wrote TDD Design Starter Kit - Dependency Inversion Principle
on Fri, Mar 20 2009 8:06 PM

You've been kicked (a good thing) - Trackback from DotNetKicks.com

Add a Comment

(required)  
(optional)
(required)  
Remember Me?