users@jersey.java.net

Re: [Jersey] unit test a jersey resource with mocked spring beans

From: Martin Grotzke <martin.grotzke_at_freiheit.com>
Date: Tue, 22 Jul 2008 22:18:25 +0200

Hi Peter,

we're also mocking our spring beans, using an AbstractResourceMockTest
like the one below.

Cheers,
Martin


public abstract class AbstractResourceMockTest {

    private Map<Class<?>, Object> _mockObjects;

    public AbstractResourceMockTest() {
        this(new HashMap<Class<?>, Object>());
    }

    public AbstractResourceMockTest( Map<Class<?>, Object> mockObjects ) {
        _mockObjects = mockObjects;
    }
    
    @Override
    protected void registerContext(String servletPath, Context context){
        
        final Map<String,String> contextParams = new HashMap<String, String>();
        contextParams.put( "contextConfigLocation", "classpath:applicationContext.xml" );
        context.setInitParams( contextParams );
        
        final ServletHolder springServletHolder = new ServletHolder( ContextLoaderServlet.class );
        springServletHolder.setInitOrder( 1 );
        context.addServlet( springServletHolder, "/*" );
        
        final ServletHolder springMockServletHolder = new ServletHolder( new SpringMockServlet( _mockObjects ) );
        springMockServletHolder.setInitParameter( "com.sun.jersey.config.property.resourceConfigClass",
                PackagesResourceConfig.class.getName() );
        springMockServletHolder.setInitParameter( PackagesResourceConfig.PROPERTY_PACKAGES,
                "com.company.proj.api" );
        springMockServletHolder.setInitOrder ( 2 );
        context.addServlet(springMockServletHolder, servletPath + "/*");
        
        
        final FilterHolder holder = context.addFilter( DelegatingFilterProxy.class, "requestContextFilter", 1 );
        holder.setInitParameter( "targetBeanName", "requestContextFilter" );
        
        final FilterHolder securityContextFilterHolder = context.addFilter(DelegatingFilterProxy.class, "/*", org.mortbay.jetty.Handler.REQUEST);
        securityContextFilterHolder.setInitParameter( "targetBeanName", "apiSecurityContextFilter" );
    }

    /**
     * A servlet capable of using mockup Objects.
     */
    static class SpringMockServlet extends com.sun.jersey.spi.spring.container.servlet.SpringServlet {
        
        private static final Log LOG = LogFactory.getLog(SpringMockServlet.class);

        private static final long serialVersionUID = -1558204526904943255L;

        private final Map<Class<?>, Object> _mockObjects;

        public SpringMockServlet(Map<Class<?>, Object> mockObjects) {
            _mockObjects = mockObjects;
        }

        /**
         * Registers the mockup component provider.
         * @see com.sun.jersey.spi.container.servlet.ServletContainer#initiate(com.sun.jersey.api.core.ResourceConfig, com.sun.jersey.spi.container.WebApplication)
         */
        @Override
        protected void initiate(ResourceConfig rc, WebApplication wa) {
            try {
                final org.springframework.web.context.WebApplicationContext springContext = WebApplicationContextUtils.
                getRequiredWebApplicationContext( getServletContext() );

                wa.initiate(rc, new SpringMockSupportComponentProvider(
                        (ConfigurableApplicationContext) springContext, _mockObjects ));

            } catch( RuntimeException e ) {
                LOG.error( "Got exception while trying to initialize", e );
                throw e;
            }
        }

        /**
         * Replaces the ComponentProvider with one providing mockup components.
         */
        static class SpringMockSupportComponentProvider extends SpringComponentProvider {

            private final Map<Class<?>, Object> _mockObjects;

            public SpringMockSupportComponentProvider(
                    ConfigurableApplicationContext applicationContext, Map<Class<?>, Object> mockObjects ) {
                super( applicationContext );
                _mockObjects = mockObjects;
            }

            /* (non-Javadoc)
             * @see com.sun.jersey.spi.spring.container.servlet.SpringServlet.SpringComponentProvider#getInstance(com.sun.jersey.spi.service.ComponentProvider.Scope, java.lang.Class)
             */
            @Override
            public <T> T getInstance( Scope scope, Class<T> type )
            throws InstantiationException, IllegalAccessException {
                final Object obj = _mockObjects.get( type );
                if ( obj != null ) {
                    return type.cast( obj );
                }

                return super.getInstance( scope, type );
            }

            /* (non-Javadoc)
             * @see com.sun.jersey.spi.spring.container.servlet.SpringServlet.SpringComponentProvider#getInstance(com.sun.jersey.spi.service.ComponentContext, com.sun.jersey.spi.service.ComponentProvider.Scope, java.lang.Class)
             */
            @Override
            public <T> T getInstance( ComponentContext cc, Scope scope, Class<T> type ) throws InstantiationException,
                    IllegalAccessException {
                
                final Object obj = _mockObjects.get( type );
                if ( obj != null ) {
                    return type.cast( obj );
                }
                
                return super.getInstance( null, scope, type );
            }

        }

    }

    public Map<Class<?>, Object> getMockObjects() {
        return _mockObjects;
    }
    
    public <T> void addMockObject( Class<T> clazz, T mockObject ) {
        _mockObjects.put( clazz, mockObject );
    }
    
    public <T> T removeMockObject( Class<T> clazz ) {
        return clazz.cast( _mockObjects.remove( clazz ) );
    }
    
    public void clearMockObjects() {
        _mockObjects.clear();
    }
    
}

This can be used like this:

public class UsersResourceTest extends AbstractResourceMockTest {
    
    private APIUsersFacade _facade;
    
    @BeforeClass
    public void setUpClass() {
        _facade = EasyMock.createMock(APIUsersFacade.class);

        addMockObject( APIUsersFacade.class, _facade );
    }

    ...

}

On Tue, 2008-07-22 at 12:20 +0200, Peter De Koster wrote:
> Hi,
>
> I'm using spring 2.5.5 and jersey 0.8-ea and it works nicely.
> I'd like to test my resource classes using the HttpServerFactory +
> Client classes.
> To do this I need to mock the injected spring beans (for several
> reasons - among others because it's an ear project..).
> My question is how ? Has anything been provided for this, or scheduled
> to be provided, or could anyone propose an alternative
>
> Kind regards,
>
> Peter