/ FACTORYBEAN, MOCKITO, PROXY, SPRING, SPY, STUB, STUBBING, UNIT TESTING

Mockito' spy() method and Spring

Mockito is a mocking framework (see Two different mocking approaches) that is an offshoot of EasyMock. Whatever the mocking framework one uses, a common feature is the ability to mock interfaces, through the JDK Proxy class. This is well and nice, but one has to explicitly mock every method that one wants to use in the course of the test.

What if I want to mock an already existing implementation, with some methods providing behaviours that suit me ? Today, I ran across this case: I had a legacy helper class I wanted to reuse. This class used commons-http-client to ease the process of calling an URL. It had property accessors, like any good old POJO, that I really needed even in the test scope and a method that made the real call, using previously set properties (such as URL). It implemented no interface, though. Here’s what it looked like:

public class LegacyHelper {

    // Various attributes
    ...

    // Various accessors to get/set these properties
    ...

    // One big method that uses external resources (very bad for Unit Testing)
    public int callUrl() {
        ...
    }
}

Although Mockito lacks exhaustive documentation (a trait shared by many Google Code projects, much to my dismay), I happened to run across the Mockito.spy() method. This magic method creates a proxy (hence the name spy) on a real object. It delegates its method calls to the proxied object unless these methods are stubbed. It means I could rely on the getters/setters doing their work while neutralizing the legacy method that broke isolation testing.

public class MyTest {

    // This I don't want to test but my class uses it
    private LegacyHelper helper;

    @BeforeMethod
    public void setUp() {
        helper = Mockito.spy(new LegacyHelper());
        Mockito.when(helper.callUrl()).thenReturn(0);
    }

    @Test
    public void testCall() {
        // Now I can use helper without it really calling anything
        helper.callUrl();
        // Do real testing here
       ...
    }
}

This is only the first step. What if I need to provide spied objects throughout the entire application? Spring certainly helps here with the FactoryBean interface. When Spring creates a new instance, either it calls the new operator or the getObject() method if the referenced class is of type FactoryBean. Our spy factory looks like this:

public class SpyFactoryBean {

    // Real or spied object
    private Object real;

    public void setReal(Object object) {
        real = object;
    }

    public boolean isSingleton() {
        return false;
    }

    public Class getObjectType() {
        return real.getClass();
    }

    public Object getObject() {

        return Mock.spy(real);
    }
}

To use it in a Spring context file:

<?xml version="1.0" encoding="ISO-8859-1"?>
<beans>
    <bean id="legacyHelper" class="LegacyHelper" />
    <bean id="mockHelper" class="SpyFactoryBean" dependency-check="objects">
        <property name="real" ref="legacyHelper" />
    </bean>
</beans>

Now you’ve got a factory of spies that you can reuse across your project’s tests or even better, ship for use among all your enterprise’s projects. The only thing to do is not to forget to stub the methods that may have side-effects.

Nicolas Fränkel

Nicolas Fränkel

Developer Advocate with 15+ years experience consulting for many different customers, in a wide range of contexts (such as telecoms, banking, insurances, large retail and public sector). Usually working on Java/Java EE and Spring technologies, but with focused interests like Rich Internet Applications, Testing, CI/CD and DevOps. Also double as a trainer and triples as a book author.

Read More
Mockito' spy() method and Spring
Share this