在使用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 上下文中,您定义此处理器,而在集成测试的上下文中,此后处理器将不存在。