Using the Proxy Pattern for Unit Testing

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.

Screen Shot 2013-11-17 at 9.38.38 PM

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:

  1. It has a parameterless constructor
  2. 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!

When Spring DI Becomes Evil

I recently started to work on an Open Source SIP project called OpenMRS, and realised that most (if not all) of the unit tests are actually integration tests. The way the OpenMRS code (and test) base uses the Spring IoC is I believe a large part of the problem. Although I am not a big fan of DI, I think there is value in using the Spring IoC in some cases. But there are some pitfalls to avoid, and good practices to follow.

The OBFA Factor

Nowadays, spring contexts seem to be so embedded in Java applications that developers forget that they are meant to be treated parsely, and with caution. One good example of this symptom is the one-big-fat-a*** (OBFA) applicationContext file for the entire stack. Having an OBFA spring context file makes the customisation of parts of it more difficult and dangerous.

Instead, it is preferable to split the contexts into smaller files, so that a layer, or a part of the stack, can be independently reimplemented or reconfigured. As an example, a sample Java app (cashman) I keep for demo purpose has:

  • spring-appcontext.xml Root Spring context file e.g.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">

<import resource="classpath:spring-datasource.xml"/>
<import resource="classpath:spring-txmanager.xml"/>
<import resource="classpath:spring-hibernate.xml"/>
<import resource="classpath:spring-dao.xml"/>
<import resource="classpath:spring-cashmachine.xml"/>

</beans>
  • spring-cashmachine.xml Domain Service config e.g.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">

<bean name="cashMachine" factory-method="getInstance">
    <property name="stockDAO" ref="stockDAO" />
</bean>

</beans>
  • spring-dao.xml DAO config e.g.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">

<bean id="stockDAO">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

</beans>
  • spring-datasource.xml Database connection config e.g.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="dataSource" destroy-method="close">
    <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
    <property name="url" value="jdbc:hsqldb:mem:spring-playground"/>
    <property name="username" value="sa"/>
    <property name="password" value=""/>
</bean>

</beans>
  • spring-hibernate.xml Hibernate config e.g.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="sessionFactory">
    <property name="dataSource" ref="dataSource" />
    <property name="annotatedClasses">
        <list>
            <value>com.suncorp.cashman.persistence.StockItem</value>
        </list>
    </property>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect"> org.hibernate.dialect.HSQLDialect</prop>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.hbm2ddl.auto">create</prop>
        </props>
    </property>
</bean>

</beans>
  • spring-txmanager.xml Transaction Manager config e.g.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="txManager" name="txManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

</beans>

Doing so enables creating and swapping environment-specific spring configs. The idea is to make environment-specific the configuration elements that will change often. In my case spring-datasource.xml and spring-hibernate.xml are good candidates. So the config contextes be structured as follows:

With this structure, if the app is deployed locally, then the build script will take the spring files in the dev directory. Similarly, if unit tests are run (e.g. in your build pipeline), the files in test would be put on the classpath.

Hence, if developers want to use a local mysql instance, they can configure the dev/spring-datasource.xml file with the following line:

<property name="url" value="jdbc:hsqldb:hsql://localhost:9001"/>

For speed’s sake, unit tests would preferably run on an in-memory database, hence test/spring-datasource.xml would have:

<property name="url" value="jdbc:hsqldb:mem:spring-playground"/>

Note: A similar approach would be to override the default spring config using the @ContextConfiguration Spring 3 annotation. For instance, one could create a supertype class for all the integration tests to load the test-specific context as follows:

@ContextConfiguration(locations={"classpath:spring-test-*.xml"})
public class MyUnitTestBaseClass { }

In that case, each test-specific spring config file’s name starts with spring-test. So the files can stay on the classpath (no need to swap through build script), as they will not clash with the default config, and will only be used by unit tests.

When Spring Hides The Mocking Game

Most OpenMRS JUnit tests extend BaseContextSensitiveTest, which loads the Spring context applicationContext-service.xml for the Application Services, hence automatically wiring the DAOs.

@ContextConfiguration(locations = { "classpath:applicationContext-service.xml", "classpath*:openmrs-servlet.xml",
"classpath*:moduleApplicationContext.xml" })
@TestExecutionListeners( { TransactionalTestExecutionListener.class, SkipBaseSetupAnnotationExecutionListener.class,
StartModuleExecutionListener.class })
@Transactional
public abstract class BaseContextSensitiveTest extends AbstractJUnit4SpringContextTests { [...] }

Because of that, the service unit tests do not mock nor stub the DAOs. The first issue here is that they are not unit tests but integration tests. The second issue is that it becomes very difficult to write proper unit tests (with mocked dependencies) using the same context without breaking other tests.

Indeed, I was trying to add the following test method to ProgramWorkflowServiceTest:

@Test
@Verifies(value="should call the DAO method getProgramsByName", method = "getProgramByName")
public void getProgramByName_shouldCallDaoGetProgramsByName() {     
    ProgramWorkflowDAO mockDao = Mockito.mock(ProgramWorkflowDAO.class);
    pws.setProgramWorkflowDAO(mockDao);
    pws.getProgramByName("A name");
    Mockito.verify(mockDao).getProgramsByName("A name");
}

pws is an instance of ProgramWorkflowService obtained from the Spring context. By doing so, I actually ended up screwing-up all other subsequent unit tests whose class under tests depends on ProgramWorkflowService (since dependencies are obtained from the same context).

As an example, all unit tests for the following method in ProgramEditor will fail because Context.getProgramWorkflowService() at line 7 will return an object that has a mocked DAO:

1. public void setAsText(String text) throws IllegalArgumentException {
2.    if (StringUtils.hasText(text)) {
3.        try {
4.            if (text.startsWith("concept.")) {
5.                Integer conceptId = Integer.valueOf(text.substring(text.indexOf('.') + 1));
6.                Concept c = Context.getConceptService().getConcept(conceptId);
7.                setValue(Context.getProgramWorkflowService().getProgramByName(c.getName().getName()));
8.            } 
9.            else {
10.               Integer programId = Integer.valueOf(text);
11.               setValue(Context.getProgramWorkflowService().getProgram(programId));
12.           }
13.        }
[...]
}

So, by mocking a dependency of my object under test, I unexpectedly modify the behaviour of the code in another part of the application!

Make Spring DI Less Evil

To conclude, my recommendations for a more pragmatic and flexible Spring IoC config:

1. Split config files into small files, and make environment specific those that need to be.
2. Use the IoC only for integration tests, in which case use the @ContextConfiguration annotation on a layer supertype of all your integration tests.
3. Do not use the IoC for unit tests: instantiate, mock, and inject through setters in the @Before method manually.