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

半城伤御伤魂 提交于 2019-12-03 03:03:24

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

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.

For the Jersey 2.X users, here's what worked for me:

  public class AccountResourceTest extends JerseyTest {

    private ApplicationContext context;

    private BeanA beanA;

    private BeanB beanB;

    public AccountResourceTest() throws TestContainerException {
        super();

        beanA = context.getBean(BeanA.class);
        beanB = context.getBean(BeanB.class);
    }

    @Override
    protected Application configure() {
        context = new AnnotationConfigApplicationContext(SpringConfiguration.class);
        final ResourceConfig config = new JerseyConfiguration().property("contextConfig", context);
        return config;
    }

    @Override
    protected void configureClient(final ClientConfig config) {
        config.register(JacksonJsonProvider.class);
    }

    ...
}

This allows me to use JavaConfig for my Jersey tests, and access the beans in the context as well. Here's the link to where I got the idea: http://geowarin.github.io/spring-boot/jersey/2014/01/31/a-simple-spring-boot-and-jersey-application.html

With Jersey version 2.4.x, the class JerseyConfiguration does not exist anymore and has been replaced by ResourceConfig which does not understand the contextConfig property. Here is my solution :

package ch.vd.test;

import java.net.URI;

import javax.ws.rs.core.Application;

import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.jersey.server.ApplicationHandler;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.glassfish.jersey.test.grizzly.GrizzlyTestContainerFactory;
import org.glassfish.jersey.test.spi.TestContainer;
import org.glassfish.jersey.test.spi.TestContainerException;
import org.glassfish.jersey.test.spi.TestContainerFactory;
import org.junit.Test;
import org.springframework.context.ApplicationContext;

public class ExampleTest extends JerseyTest {

    private ServiceLocator serviceLocator;

    @Override
    public void setUp() throws Exception {
        super.setUp();
        final ApplicationContext context = serviceLocator.getService(ApplicationContext.class, "SpringContext");
        final Object bean = context.getBean("someBean");
    }

    @Override
    protected Application configure() {
        final ResourceConfig config = new ResourceConfig(RestResources.class);
        config.property("contextConfigLocation", "classpath:example-context.xml");
        return config;
    }

    @Override
    protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
        return new GrizzlyTestContainerFactory() {
            @Override
            public TestContainer create(URI uri, ApplicationHandler appHandler) throws IllegalArgumentException {
                serviceLocator = appHandler.getServiceLocator();
                return super.create(uri, appHandler);
            }
        };
    }

    @Test
    public void testStuff() throws Exception {
        ...
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!