July 27, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Writing More Testable Code with Dependency Injection

  • October 6, 2006
  • By Daniel Gartner
  • Send Email »
  • More Articles »

Setter Injection

In the previous example, we passed the dependencies via constructor to the object that contained the dependencies. With setter injection I set the specific implementation of the dependencies via setter methods. We'll go ahead and follow convention and use C# properties instead of getter and setter methods. We accomplish this technique by creating a property for each dependency of the class. This technique provides some added flexibility over constructor injection, since I can change the implementation of a dependency of a specific instance of a class, without having to create a new instance of that class. However, this technique is somewhat dangerous, since I need to be sure to set the specific implementation of the dependency before calling any methods that rely on any of those dependencies.

Listing 5: Setter Injection using Properties

public class PropertyManager
{
   //the IPropertyDataManager is a dependency of this class...
   private IPropertyDataManager dataManager;
   public IPropertyDataManager DataManager
   {
      get { return dataManager; }
      set { dataManager = value; }
   }

   //the ILogger is another dependency of this class
   private ILogger logger;
   public ILogger Logger
   {
      get { return logger; }
      set { logger = value; }
   }

   public PropertyManager()
   {
   }

   #region Methods that use the dependencies
   public int Add(PropertyInfo pi)
   {
      //todo: perform some validation
      int pID = this.DataManager.AddProperty(pi);
      this.Logger.WriteLog("Added Property " + pID);
      return pID;
   }

   public bool Delete(PropertyInfo pi)
   {
      this.Logger.WriteLog("Deleting Property " + pi.ID);
      return this.DataManager.DeleteProperty(pi);
   }

   public IList<PropertyInfo> GetPropertList()
   {
      return this.DataManager.GetAllProperties();
   }

   public bool Update(PropertyInfo pi)
   {
      bool didUpdate = this.DataManager.UpdateProperty(pi);
      return didUpdate;
   }
   #endregion
}

Client code that uses the PropertyManager now has complete control over its dependencies. Below is an example of client code configuring a PropertyManager by specifying the implementations of its dependencies using setter injection.

Listing 5: Configuring the PropertyManager via Setter Injection

PropertyManager myManager = new PropertyManager();
//use one implementation of DataManager
myManager.DataManager = new DbPropertyDataManager();
myManager.GetPropertyList();

//use a different implementation of DataManager
myManager.DataManager = new ListDataProperyManager();
myManager.GetPropertyList();

Interface Injection

A third technique for dependency injection, interface injection, requires that classes implement an explicit interface. For example, since my PropertyManager has a dependency on both its IPropertyDataManager and its ILogger member variable, I would specify two new interfaces, IPropertyDataManagerInjectable and ILoggerInjectable which would each then be implemented by the PropertyManager class.

Listing 6: Interfaces for Interface Injection

interface ILoggerInjectable
{
   void SetLogger(ILogger l);
}

interface IPropertyDataManagerInjectable
{
   void SetPropertyDataManager(IPropertyDataManager pdm);
}

The implementation of these interfaces simply sets the member variables with the parameter that is passed to the methods of the interface.

Listing 7: Implementing the Interfaces

public class PropertyManager : IPropertyDataManagerInjectable,
   ILoggerInjectable
{
   //the IPropertyDataManager is a dependency of this class...
   private IPropertyDataManager dataManager;
   //the ILogger is another dependency of this cass
   private ILogger logger;

   #region IPropertyDataManagerInjectable Members
   public void SetPropertyDataManager(IPropertyDataManager pdm)
   {
      this.dataManager = pdm;
   }
   #endregion

   #region ILoggerInjectable Members
   public void SetLogger(ILogger l)
   {
      this.logger = l;
   }
   #endregion

   public PropertyManager()
   {
   }
      

//...PropertyManager's methods }

Client code that uses the PropertyManager injects dependencies using the methods specified in the implementation of the interfaces.

Listing 8: Configuring the PropertyManager via Interface Injection

PropertyManager myManager = new PropertyManager();
myManager.SetLogger(new SimpleLogger());
myManager.SetPropertyDataManager(new ListDataProperyManager());
myManager.GetPropertyList();

Possible Enhancements

The provided examples set the different implementation of PropertyManager's dependencies through code. However, with a little effort, you could rig the application to inject its dependencies based on a configuration file. This would increase overall flexibility of the application and would not require recompilation each time the injected dependency is modified. Also, there are several frameworks available that can be used to handle dependency injection for you. A couple frameworks of note are StructureMap and ObjectBuilder, I urge you to investigate them to see if they might meet your needs.

Conclusion

Code that follows the dependency injection design pattern is more testable because the dependencies of a class under test are abstracted outside of that class. This inversion of control decouples the code from external dependencies such as databases, file and network I/O operations that typically inhibit testing. This enables client code that uses the class to specify the actual implementation of the dependencies that they need and leads to code that is more flexible and easier to maintain.

You can download the code here.

About the Author

Dan Gartner is a Senior Consultant with Crowe Chizek and Company, LLC and lives in Chicago, IL. He specializes in designing and developing applications for rapidly evolving organizations using Microsoft technologies.



Page 2 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel