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



在使用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>

为了定义prototype作用域实现支持的request作用域,我想将类更改为prototype作用域的实现。但是我找不到任何。

查看范围接口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() {
        ...
事实上,

它以不同的方式工作 - 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;
}

当然,有几种方法可以创建豆子 - 你可以在这里找到 http://www.kubrynski.com/2013/09/injecting-spring-dependencies-into-non.html

这样

的东西不适合你?

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

也许你可以走另一条路?

编写一个 beanfactorypostprocessor 将请求范围的 Bean 候选更改为原型怎么样?

我自己还没有尝试过,但您应该能够将其应用于任何声明为请求范围的 bean 并设置原型标志。

在单元测试的 Spring 上下文中,您定义此处理器,而在集成测试的上下文中,此后处理器将不存在。

最新更新