Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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>
like image 519
robert.andre.brink Avatar asked Aug 16 '13 21:08

robert.andre.brink


2 Answers

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).

like image 150
Michal Gajdos Avatar answered Nov 02 '22 23:11

Michal Gajdos


You can inject your test class to Jersey context if you don't have any objections for that.

For example:

@Override
protected Application configure() {
    final TestJerseyApplication application = new TestJerseyApplication();

    final Map<String, Object> properties = new HashMap<>();
    properties.put("contextConfigLocation", "classpath:test-spring-context.xml");
    application.setProperties(properties);

    application.register(this);
    return application;
}

After that the @Autowired annotation will work for you.

like image 28
Damal Avatar answered Nov 03 '22 00:11

Damal