Search code examples
javaspringunit-testingjersey-2.0

Retrieve a managed bean from a JerseyTest container with jersey-spring3


This question is a follow on from a previous question Specify Custom Application Context.

We are migrating some of our data services from Jersey 1.x using jersey-spring to Jersey 2.x using jersey-spring3.

We have a few test classes that inherit from JerseyTest. Some of these classes use custom applicationContext.xml files that are not specified in the web.xml file.

For object mocking purposes we would mock out some components in our Jersey Resources.

In Jersey 1.x we could mock objects in the application context file by

<bean id="mockBean" class="org.easymock.EasyMock" 
    factory-method="createStrictMock" autowire="byName">
    <constructor-arg index="0" value="com.xxx.xxx.ClassToMock" /> 
</bean>

and retrieve these mocked instances as follows

ClassToMock obj = (ClassToMock)ContextLoader
    .getCurrentWebApplicationContext()
    .getAutowireCapableBeanFactory()
    .getBean("mockBean");

How can the same be achieved with Jersey 2.x using jersey-spring3?

I have combed through the API docs, user guides and some of the sources but was unable to find an answer.

Thank you.

EDIT:

We will be using the mocked beans inside of our JAX-RS resources. We have service interfaces that are @Autowired into our resources.

e.g.

@Path(ProductResource.RESOURCE_PATH)
@Component
@Scope("prototype")
public class ProductResource 
extends GenericResource<Product, BaseModel> {

    /*
     * Members
     */

    public static final String RESOURCE_PATH = "product/";

    @Autowired
    protected ProductService productService;

    ...

We want to mock out the and set the expectations on these services.

e.g.

<bean id="productService" class="org.easymock.EasyMock" 
    factory-method="createStrictMock">
    <constructor-arg index="0" 
        value="com.xxx.xxx.service.ProductService" /> 
</bean>

Solution

  • Note: I am not a Spring expert and I consider this to be rather a work-around than a recommended approach. Hopefully someone will come up with a better solution.

    You can't obtain an ApplicationContext instance by calling ContextLoader#getCurrentWebApplicationContext() because Jersey 2.x runtime is by default initialized outside of a Servlet container when using Jersey Test Framework (JerseyTest) for unit/e2e tests.

    In this case you need to use a little work-around to obtain an ApplicationContext by implementing an ApplicationContextAware interface in your test package:

    public class ApplicationContextUtils implements ApplicationContextAware {
    
        private static ApplicationContext applicationContext;
    
        public static ApplicationContext getApplicationContext() {
            return applicationContext;
        }
    
        @Override
        public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
            ApplicationContextUtils.applicationContext = applicationContext;
        }
    }
    

    Once you have this class, don't forget to mention it in your application context descriptor:

    ...
    <bean class="org.glassfish.jersey.examples.helloworld.spring.ApplicationContextUtils" />
    ...
    

    And you can use it in your tests:

    public class JerseySpringResourceTest extends JerseyTest {
    
        // ... Configure ...
    
        @Before
        public void mockUp() throws Exception {
            // ApplicationContext is ready in your @Before methods ...
            assertThat(ApplicationContextUtils.getApplicationContext(), notNullValue());
        }
    
        @Test
        public void testJerseyResource() {
            // ... as well as in your test methods.
            assertThat(ApplicationContextUtils.getApplicationContext(), notNullValue());
        }
    }
    

    Note: If you want to deploy your application to a Servlet container and run your (JerseyTest) tests against it, consult Jersey Test Framework chapter in the Users Guide (especially External container section).