9

这个问题是上一个问题Specify Custom Application Context的后续问题。

我们正在将我们的一些数据服务从使用 jersey-spring 的 Jersey 1.x 迁移到使用 jersey-spring3 的 Jersey 2.x。

我们有几个继承自 JerseyTest 的测试类。其中一些类使用 web.xml 文件中未指定的自定义 applicationContext.xml 文件。

出于对象模拟的目的,我们将模拟我们 Jersey 资源中的一些组件。

在 Jersey 1.x 中,我们可以通过以下方式模拟应用程序上下文文件中的对象

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

并按如下方式检索这些模拟实例

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

使用 jersey-spring3 的 Jersey 2.x 如何实现同样的效果?

我已经梳理了API 文档用户指南和一些来源,但无法找到答案。

谢谢你。

编辑:

我们将在 JAX-RS 资源中使用模拟 bean。我们的资源中有服务接口@Autowired

例如

@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;

    ...

我们想模拟并设定对这些服务的期望。

例如

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

4 回答 4

8

注意:我不是 Spring 专家,我认为这是一种解决方法,而不是推荐的方法。希望有人会提出更好的解决方案。

您无法ApplicationContext通过调用获取实例,ContextLoader#getCurrentWebApplicationContext()因为当使用 Jersey 测试框架 ( JerseyTest) 进行单元/e2e 测试时,Jersey 2.x 运行时默认在 Servlet 容器之外初始化。

在这种情况下,您需要使用一些变通方法来通过在测试包中ApplicationContext实现ApplicationContextAware接口来获得:

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;
    }
}

一旦你有了这个类,不要忘记在你的应用程序上下文描述符中提到它:

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

您可以在测试中使用它:

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());
    }
}

注意:如果您想将应用程序部署到 Servlet 容器并JerseyTest针对它运行 () 测试,请参阅用户指南中的Jersey 测试框架章节(尤其是外部容器部分)。

于 2013-08-17T13:27:38.550 回答
3

如果您对此没有任何异议,您可以将您的测试类注入 Jersey 上下文。

例如:

@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;
}

之后,@Autowired注释将为您工作。

于 2015-06-02T15:04:12.580 回答
1

在 Jersey 版本 2.4.x 中,该类JerseyConfiguration不再存在并且已被替换为ResourceConfig不理解contextConfig属性的类。这是我的解决方案:

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 {
        ...
    }
}
于 2014-06-26T06:13:33.983 回答
1

对于 Jersey 2.X 用户,这对我有用:

  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);
    }

    ...
}

这允许我在我的 Jersey 测试中使用 JavaConfig,并且还可以访问上下文中的 bean。这是我得到这个想法的链接:http: //geowarin.github.io/spring-boot/jersey/2014/01/31/a-simple-spring-boot-and-jersey-application.html

于 2014-03-15T21:48:33.020 回答