Understanding an Object Oriented Programming design pattern requires having a clear and specific use case for which you would apply it. Here is one for the Proxy Pattern.
The Proxy Pattern as described in the Gang Of Four book does:
Allow for object level access control by acting as a pass through entity or a placeholder object.
Although it is one of the simplest of all patterns (maybe with the Singleton Pattern), this description remains nebulous. The simple drawing below attempts to provide a clearer picture. As in real life, the proxy is a middle man, here between an API and some client code.
The question is: if the proxy does nothing but delegating to the API (unlike the Adapter Pattern or the Facade Pattern), what do I need a proxy for? Shall I not just call the API directly?
Let’s look at the case where you have no control over the API, for instance if you use a third party library, or even an internal library whose source code you do no have access to. A recent example I came across is the use of the C# UrlHelper
API in a .NET MVC project. The Action()
method below returns a URI as a string given the controller name, the action name, and the query string parameters as a hash:
string Action(string action, string controller, object routeValues)
Therefore, a call to:
urlHelper.Action("Products", "View", new {store = "BrisbaneCity"})
will return:
http://myapp.mydomain.com/products/view?store=BrisbaneCity
The TrackerController
below has an explicit dependency on UrlHelper
. The Registration()
action method sets the URL of the mobile site back button using the UrlHelper.Action()
method.
using System.Web.Mvc; public class TrackerController : Controller { private UrlHelper UrlHelper { get; set; } public TrackerController(UrlHelper urlHelper) { UrlHelper = urlHelper; } [...] [HttpGet] public ActionResult Registration(Guid? order) { ViewBag.MobileBackButtonUrl = UrlHelper.Action("Index", "Tracker", new { order }); [...] } [...] }
A unit test that checks the MobileBackButtonUrl
property of the ViewBag
would look like that:
[TestClass] public class TrackerControllerTest { private Mock<UrlHelper> mockUrlHelper; private TrackerController trackerController; [TestInitialize] public void Initialize() { mockUrlHelper = new Mock<UrlHelper>(); trackerController = new TrackerController(mockUrlHelper); } [...] [TestMethod] public void Registration_SetsTheMobileBackButtonUrl() { var testUrl = "http://thebackbuttonurl" mockUrlHelper.Setup(h=>h.Action("Index", "Tracker", It.IsAny()).Return(testUrl); var result = trackerController.Registration(new Guid()); Assert.AreEqual(testUrl, result.ViewBag.MobileBackButtonUrl; } [...] }
Unfortunately, because the UrlHelper
does not have a parameterless constructor, it cannot be mocked using the C# Moq
library. Even it it had a parameterless constructor, the Action()
method not being virtual will prevent Moq
from stubbing it. The bottom line is: it is very hard to unit test a class that has dependencies on third party APIs.
So, let’s use the Proxy Pattern to make our testing easier. The idea is the create a proxy for the UrlHelper
class. We’ll call it UrlHelperProxy
.
using System; using System.Web.Mvc; using System.Web.Routing; namespace Dominos.OLO.Html5.Controllers { public class UrlHelperProxy { private readonly UrlHelper helper; public UrlHelperProxy() {} public UrlHelperProxy(UrlHelper helper) { this.helper = helper; } public virtual string Action(string action, string controller, object hash) { return helper.Action(action, controller, hash); } } }
As you can see the UrlHelperProxy
does nothing fancy but delegating the Action()
method to the UrlHelper
. But what it does differently is:
- It has a parameterless constructor
- The
Action()
method is virtual
Therefore, by changing the TrackerController
code to accept injection of an UrlHelperProxy
instead of UrlHelper
, we will be able to appropriately unit test the Registration()
method.
using System; using System.Web.Mvc; public class TrackerController : Controller { private UrlHelperProxy UrlHelper { get; set; } public TrackerController(UrlHelperProxy urlHelper) { UrlHelper = urlHelper; } [...] }
—
[TestClass] public class TrackerControllerTest { private Mock<UrlHelperProxy> mockUrlHelper private TrackerController trackerController; [TestInitialize] public void Initialize() { mockUrlHelper = new Mock<UrlHelperProxy>(); trackerController = new TrackerController(mockUrlHelper); } [...] }
I am always in favour of changing a design to improve testability. An example is the provision of setter injectors to some of the properties that the unit test need to alter/stub. It usually pays off by providing a deeper understanding of the code and some of the design considerations to be had.
Here is a simple example that illustrate a well known and simple Object Oriented Design Pattern. We made our TrackerController
class more testable, and we understand better what the Proxy Pattern can be used for: win win!