Introduction
When I first discovered Dependency Injection, it changed the way I wrote code. It made Test Driven Development possible, coupled with mocking dependencies in unit tests.
In those early days, I was often frustrated when I had a dependency that I couldn't inject, which means I couldn't mock it out in my unit tests. This article goes through three examples
that I experienced and shows how the Proxy Pattern can be used as a solution to these scenarios.
Background
This article assumes you are already comfortable with dependency injection and how it works.
To learn more about the Proxy Pattern, see this article.
It's worth noting two points relating to this article:
- Some descriptions of the Proxy Pattern talk about the real object sharing the same interface as the proxy object. I'm not doing that, as will be obvious in the scenarios below.
- Many frameworks offer built-in solutions for the scenarios below, so you don't necessarily need to use the Proxy Pattern (in particular, the third scenario,
string
parameters in the constructor).
Scenarios Illustrating the Problem
Here are three different scenarios that I have run into in the past:
Can't Mock Static Methods
In one application I wrote, I needed to use the File
object from the .NET framework to save and open files. File
is a static
class with static
methods for Create
and Open
. I needed to stub these methods so that objects that were dependent upon File
could be tested in isolation (e.g. run without needing to actually open and create a file). Mocking frameworks, like Rhino Mocks and MOQ, can't mock or stub a static
method.
Can't Mock Extension Methods
I spent a lot of the past few years writing Silverlight and WPF applications, using the excellent PRISM framework to implement MVVM. One of the great features of this framework is the Navigation module. In my ViewModel
tests, I wanted to assert that a navigation is called by RegionManager.RequestNavigate
. Although RegionManager
has an interface which can be mocked, RequestNavigate
is an extension method. Mocking frameworks, like Rhino Mocks and MOQ, can't mock or stub an extension method.
Can't Inject Objects that Have Value Types or Strings Passed into the Constructor
A recent project involved writing a WPF application that accessed calendars using the Google Calendar service. The Google CalendarService
has a single constructor which expects a string
(used to name the application, but in my case, I just wanted it hard-coded as null). Some Dependency Injection frameworks don't know how to construct this class because there's no way to know what value the string
should be set to. In this particular project, I was using SimpleInjector
. Note, this is one example where most Dependency Injection frameworks can solve this, but I've listed it in this article to illustrate how the Proxy Pattern can also solve it.
Proxy Pattern Solutions
I've attached an example project with all the problems and solutions illustrated. To focus on the technique, I've used very trivial examples.
Static Methods
Using the following code as an example of a static
class.
public static class CannotInjectStatic
{
public static bool GreaterThanFive(int number)
{
return number > 5;
}
}
The first step is to add an interface to expose the static
method that you want to mock.
public interface ICannotInjectStatic
{
bool GreaterThanFive(int number);
}
Now implement that interface as a proxy class for the real class.
public class CannotInjectStaticProxy : ICannotInjectStatic
{
public bool GreaterThanFive(int number)
{
return CannotInjectStatic.GreaterThanFive(number);
}
}
Now the new interface and the proxy class can be registered with the Dependency Injection container and injected in objects that have a dependency on the real class.
The following example uses Unity as the Dependency Injection container.
container.RegisterType<ICannotInjectStatic, CannotInjectStaticProxy>();
The proxy class can now be mocked, so your class using the proxy class can use a mock in unit tests for asserting that calls are correct.
[Test]
public void DoSomethingInjected_calls_CannotInjectStatic()
{
_something.DoSomethingInjected();
_cannotInjectStaticProxy.AssertWasCalled(x => x.GreaterThanFive(Arg<int>.Is.Equal(6)));
}
And the mock can also return fake responses for unit tests.
[Test]
public void DoSomethingInjected_calls_CannotInjectStatic([Values(true, false)]bool isGreaterThanFive)
{
_cannotInjectStaticProxy.Expect(
x => x.GreaterThanFive(Arg<int>.Is.Anything)).Return(isGreaterThanFive);
var result = _something.DoSomethingInjected();
Assert.AreEqual(isGreaterThanFive, result);
}
Extension Methods
Using the following code as an example of a class and extension method for the class.
public class WillBeExtended
{
public string Name { get { return "Name"; } }
}
public static class CannotInjectExtension
{
public static string NamePlus(this WillBeExtended willBeExtended)
{
return willBeExtended.Name + "Plus";
}
}
Once again, we create an interface, exposing the extension method(s) we want to be able to mock. We also need to put in non-extension methods and properties from
the real class that you want to use in the proxy class.
public interface IWillBeExtendedProxy
{
string NamePlus();
string Name { get; }
}
And then we implement the interface in the proxy class.
public class WillBeExtendedProxy : IWillBeExtendedProxy
{
private readonly WillBeExtended _willBeExtended;
public WillBeExtendedProxy()
{
_willBeExtended = new WillBeExtended();
}
public string NamePlus()
{
return _willBeExtended.NamePlus();
}
public string Name { get { return _willBeExtended.Name; } }
}
And register it.
container.RegisterType<IWillBeExtendedProxy, WillBeExtendedProxy>();
And mock it.
[Test]
public void DoSomethingInjected_calls_WillBeExtended()
{
_something.DoSomethingInjected();
_willBeExtendedProxy.AssertWasCalled(x => x.NamePlus());
}
String Parameter in Constructor
Note: As noted above, this solution should only be considered if your Dependency Injection framework does
not solve it directly. Most do.
Using the following code as an example of a class with a constructor that has a string
parameter.
public class CannotInjectConstructor
{
private readonly string _name;
public CannotInjectConstructor(string name)
{
_name = name;
}
public string Name { get { return _name; } }
}
Create an interface for all the methods and properties that you want to mock.
public interface ICannotInjectConstructor
{
string Name { get; }
}
Create the proxy class, with the constructor parameter hard-coded to the value desired. Obviously this assumes that the constructor value will always be the same,
which was the case with the real world example above.
public class CannotInjectConstructorProxy : ICannotInjectConstructor
{
private readonly CannotInjectConstructor _cannotInjectConstructor;
public CannotInjectConstructorProxy()
{
_cannotInjectConstructor = new CannotInjectConstructor("name");
}
public string Name { get { return _cannotInjectConstructor.Name; } }
}
And finally, register it.
container.RegisterType<ICannotInjectConstructor, CannotInjectConstructorProxy>();
Points of Interest
The proxy interface should only expose the methods and properties you intend to use. For example, the File
class has 50+ methods, but I only needed Open
and Create
, so the interface only had those methods.
The proxy interface method and property signatures should be exactly the same as the real class. Don't be tempted
to add some logic to these interfaces or proxy classes. The proxy class cannot be tested in isolation, so its functionality should be exactly the same as the real class.
This isn't an issue because the real class should be fully tested by the third party that wrote the code (e.g. we should assume Microsoft have thoroughly tested File
).
Try to avoid creating proxy classes for your own classes. In my experience, this usually indicates there's a design issue (e.g. you've used an extension method to extend your
own code - rather than creating a proxy, change the extension method to be a normal method). The only time I've broken this rule is when enhancing a legacy application where the original
code could not be altered.
To see the above code in action, I've attached a solution illustrating each. I've also included the unit tests, showing how the dependencies can be mocked
and stubbed.
History
- 7 October 2013: Initial version
- 8 October 2013: Added mocking examples and further clarified when scenario 3 might be used