将请求范围定义为集成测试的原型

时间:2013-12-24 16:55:52

标签: java xml spring

在使用Spring 3.1编写集成测试时,我通常将request范围定义为SimpleThreadScope,并使用以下XML上下文配置:

<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
  <property name="scopes">
    <map>
      <entry key="request">
        <bean class="org.springframework.context.support.SimpleThreadScope" />
      </entry>
    </map>
  </property>
</bean>

要定义request范围实现支持的prototype范围,我想将类更改为prototype范围的实现。但是我无法找到任何。

查看Scope Interface Javadoc,在所有已知实现类的部分中,我看到列出:AbstractRequestAttributesScope, PortletContextScope, RequestScope, ServletContextScope, SessionScope, SimpleThreadScope...没有看起来像原型范围。

如何将请求范围定义为集成测试的原型?

更新:我已经设法通过创建我自己的原型范围来完成集成测试,我已经定义如下,所以现在我的问题是,以下实现是否正确,或者它必须修复。

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;

public class PrototypeScope implements Scope {

    private static final Log logger = LogFactory.getLog(PrototypeScope.class);

    public Object get(String name, ObjectFactory objectFactory) {
        return objectFactory.getObject();
    }

    public Object remove(String name) {
        return null;
    }

    public void registerDestructionCallback(String name, Runnable callback) {
        logger.warn("PrototypeScope does not support destruction callbacks. "
                + "Consider using a RequestScope in a Web environment.");
    }

    public Object resolveContextualObject(String key) {
        return null;
    }

    public String getConversationId() {
        return Thread.currentThread().getName();
    }

}

更新2:我正在使用TestNG,我的集成测试如下所示:

@Test
@ContextConfiguration(locations = { "classpath:META-INF/spring/test-context.xml" })
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class MyIntegrationTest extends AbstractTransactionalTestNGSpringContextTests {

    @Resource
    private MyBeanThatShouldBePrototype bean;

    @Transactional
    public void testCase() {
        ...

3 个答案:

答案 0 :(得分:2)

实际上它以不同的方式工作 - Spring检查bean是否是原型,然后克隆其定义并只填充新bean,因此没有用于保存这些bean的支持类。如果您想查看实施,请访问: org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean你会发现:

if (mbd.isPrototype()) {
    // It's a prototype -> create a new instance.
    Object prototypeInstance = null;
    try {
            beforePrototypeCreation(beanName);
            prototypeInstance = createBean(beanName, mbd, args);
    }
    finally {
        afterPrototypeCreation(beanName);
    }
    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}

如果要在测试中使用原型范围,可以通过调用新的MyObjectThatShouldBePrototype()手动创建此bean,然后使用AutowireCapableBeanFactory(注入/自动连接到测试中)将其配置为Spring bean:

@Autowired
AutowireCapableBeanFactory beanFactory;

public MyObjectThatShouldBePrototype getBean() {
    MyObjectThatShouldBePrototype bean = new MyObjectThatShouldBePrototype();
    beanFactory.autowireBean(bean);
    return bean;
}

当然有几种创建bean的方法 - 你可以在http://www.kubrynski.com/2013/09/injecting-spring-dependencies-into-non.html

找到

答案 1 :(得分:1)

这样的事情不适合你吗?

@Test
@ContextConfiguration(locations = { "classpath:META-INF/spring/test-context.xml" },
        classes = MyIntegrationTest.TestConfig.class)
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class MyIntegrationTest extends AbstractTransactionalTestNGSpringContextTests {

    @Resource
    private MyBeanThatShouldBePrototype bean; // protype bean produced by spring

    @Transactional
    public void testCase() {
        ...
    }

    @Configuration
    public static class TestConfig {
        @Bean
        @Scope(BeanDefinition.SCOPE_PROTOTYPE)
        public MyBeanThatShouldBePrototype myBeanThatShouldBePrototype() {
            return new MyBeanThatShouldBePrototype();
        }
    }
}

答案 2 :(得分:0)

也许你可以采取另一种方式?

如何编写一个将请求范围的bean候选者更改为原型的beanfactorypostprocessor呢?

我自己没有尝试过,但你应该能够将它应用于声明为请求作用域的任何bean并设置原型标志。

在单元测试的spring上下文中,您定义了此处理器,并且在集成测试的上下文中,此后处理器不会出现。