请求范围内的豆子弹测试
-
18-09-2019 - |
题
我想使用的要求范围内的豆子在我的应用程序。我使用化成junit4进行测试。如果我尝试创建一个在测试这样的:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:spring/TestScopedBeans-context.xml" })
public class TestScopedBeans {
protected final static Logger logger = Logger
.getLogger(TestScopedBeans.class);
@Resource
private Object tObj;
@Test
public void testBean() {
logger.debug(tObj);
}
@Test
public void testBean2() {
logger.debug(tObj);
}
与以下豆定义:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="java.lang.Object" id="tObj" scope="request" />
</beans>
我得到:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'gov.nasa.arc.cx.sor.query.TestScopedBeans': Injection of resource fields failed; nested exception is java.lang.IllegalStateException: No Scope registered for scope 'request'
<...SNIP...>
Caused by: java.lang.IllegalStateException: No Scope registered for scope 'request'
所以我发现这个博客,似乎有所帮助:http://www.javathinking.com/2009/06/no-scope-registered-for-scope-request_5.html
但我注意到他使用 AbstractDependencyInjectionSpringcontexttests 这似乎是使用弹簧3.0.我用弹簧2.5在这个时候,但是认为它不应该太难打开这个方法使用AbstractJUnit4SpringContextTests 作为该文件建议(确定的文档的链接3.8版本,但我采用的4.4).所以我变的 测试延伸AbstractJUnit4SpringContextTests...相同的消息。相同的问题。和现在的prepareTestInstance()方法我想要的 对复盖没有定义。好吧,也许我会把这些registerScope呼吁别的地方...所以我阅读更多关于 TestExecutionListeners 并认为会更好,因为我不想要继承的弹簧的结构。所以 我改变了我的测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:spring/TestScopedBeans-context.xml" })
@TestExecutionListeners({})
public class TestScopedBeans {
期待我会必须创建一个自定义听众,但我的时候我跑了。它的工作!伟大的,但为什么?我看不出其中的任何股票的听众 注册要求的范围或会议的范围,以及他们为什么会?没有什么要说的我想要那个呢,这可能不是一个测试软弹簧的代码...
解决方案
,则测试通过,因为它没有做任何事情:)
当省略了@TestExecutionListeners
注释,弹簧寄存器3个缺省侦听器,包括一个叫DependencyInjectionTestExecutionListener
。这是负责扫描您的测试类找东西注入,包括@Resource
注释监听器。此侦听试图注入tObj
,和失败,因为未定义范围。
在声明@TestExecutionListeners({})
,你抑制DependencyInjectionTestExecutionListener
的注册,所以测试永远不会tObj
注入可言,因为你的测试不检查tObj
的存在,它传递。
修改您的测试,使其做到这一点,它会失败:
@Test
public void testBean() {
assertNotNull("tObj is null", tObj);
}
所以你的空@TestExecutionListeners
,测试通过,因为的没有任何反应的。
现在,在你原来的问题。如果你想尝试注册与测试上下文的请求范围,然后看看对于WebApplicationContextUtils.registerWebApplicationScopes()
的源代码,你会发现行:
beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
您可以试试,看你怎么走,但可能有奇怪的副作用,因为你没有真正的意思做这一个测试。
相反,我会建议换一种方式表述您的测试,让你不要的需要的请求范围豆。这不应该是难事,@Test
的生命周期应该是没有任何长于请求范围bean的生命周期,如果你写自包含的测试。请记住,没有必要测试范围机制,它是春天的一部分,你可以假设它的作品。
其他提示
解决方案弹3.2或更新
春天开始3.2版 提供了支持,会议/请求的范围豆一体化试验.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestConfig.class)
@WebAppConfiguration
public class SampleTest {
@Autowired WebApplicationContext wac;
@Autowired MockHttpServletRequest request;
@Autowired MockHttpSession session;
@Autowired MySessionBean mySessionBean;
@Autowired MyRequestBean myRequestBean;
@Test
public void requestScope() throws Exception {
assertThat(myRequestBean)
.isSameAs(request.getAttribute("myRequestBean"));
assertThat(myRequestBean)
.isSameAs(wac.getBean("myRequestBean", MyRequestBean.class));
}
@Test
public void sessionScope() throws Exception {
assertThat(mySessionBean)
.isSameAs(session.getAttribute("mySessionBean"));
assertThat(mySessionBean)
.isSameAs(wac.getBean("mySessionBean", MySessionBean.class));
}
}
详细阅读: 请求和会议范围内的豆
解决方案春天之前3.2监听器
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestConfig.class)
@TestExecutionListeners({WebContextTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class})
public class SampleTest {
...
}
WebContextTestExecutionListener.java
public class WebContextTestExecutionListener extends AbstractTestExecutionListener {
@Override
public void prepareTestInstance(TestContext testContext) {
if (testContext.getApplicationContext() instanceof GenericApplicationContext) {
GenericApplicationContext context = (GenericApplicationContext) testContext.getApplicationContext();
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST,
new SimpleThreadScope());
beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION,
new SimpleThreadScope());
}
}
}
解决方案春天之前3.2定义范围
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestConfig.class, locations = "test-config.xml")
public class SampleTest {
...
}
TestConfig.java
@Configuration
@ComponentScan(...)
public class TestConfig {
@Bean
public CustomScopeConfigurer customScopeConfigurer(){
CustomScopeConfigurer scopeConfigurer = new CustomScopeConfigurer();
HashMap<String, Object> scopes = new HashMap<String, Object>();
scopes.put(WebApplicationContext.SCOPE_REQUEST,
new SimpleThreadScope());
scopes.put(WebApplicationContext.SCOPE_SESSION,
new SimpleThreadScope());
scopeConfigurer.setScopes(scopes);
return scopeConfigurer
}
或xml配置
test-config.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>
<map>
<entry key="session">
<bean class="org.springframework.context.support.SimpleThreadScope"/>
</entry>
</map>
</property>
</bean>
源代码
源代码,用于所有提出解决方案:
我已经尝试了多种解决方案,包括@马吕斯的用“WebContextTestExecutionListener”的解决方案,但它并没有为我工作,因为这样的代码创建请求范围之前加载应用程序上下文。
这帮助了我,到底答案是不是新的,但它是很好的: http://tarunsapra.wordpress.com/2011/06 / 28 /的junit - 弹簧 - 会话和请求范围的咖啡豆/
我简单地添加下面的代码片断到我(试验)应用程序上下文:
<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>
祝你好运!
一个溶液中,用弹簧4,进行试验时,你需要请求范围的咖啡豆,但不使经由MockMVC
任何请求,等等。
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(/* ... */)
public class Tests {
@Autowired
private GenericApplicationContext context;
@Before
public void defineRequestScope() {
context.getBeanFactory().registerScope(
WebApplicationContext.SCOPE_REQUEST, new RequestScope());
RequestContextHolder.setRequestAttributes(
new ServletRequestAttributes(new MockHttpServletRequest()));
}
// ...
测试请求作用域bean与Spring 解释很以及如何注册并创建和春天有个自定义的范围。
概括地说,如伊科恩解释的,它足以将以下添加到文本上下文配置:
<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>
代替使用预定义SimpleThreadScope,基于ThreadLocal的的,它也很容易实现自定义之一,如在文章中解释。
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
public class CustomScope implements Scope {
private final Map<String , Object> beanMap = new HashMap<String , Object>();
public Object get(String name, ObjectFactory<?> factory) {
Object bean = beanMap.get(name);
if (null == bean) {
bean = factory.getObject();
beanMap.put(name, bean);
}
return bean;
}
public String getConversationId() {
// not needed
return null;
}
public void registerDestructionCallback(String arg0, Runnable arg1) {
// not needed
}
public Object remove(String obj) {
return beanMap.remove(obj);
}
public Object resolveContextualObject(String arg0) {
// not needed
return null;
}
}
MariuszS'解决方案的工作,除了我不能得到的交易的直致力于正常。
看来新发布的3.2已经最后作出测试的请求/会议范围内的豆类,第一类的公民。这里的几个博客的更多详细信息。
森Stoyanchev的 弹簧框架3.2RC1:弹簧视测试框架
Sam感动的 弹簧框架3.2RC1:新的功能测试
不阅读该文件有时会驱动器的一个疯狂的。差不多。
如果您使用更短暂的豆子(请求的范围,例),就最有可能也需要改变你的懒惰init默认!否则WebAppContext将无法负荷,并告诉你一些有关失踪请求的范围,这当然是缺失的,因为上下文中仍装载!
弹簧们绝对应该把那暗示纳入他们的异常的消息...
如果你不想改变的默认,也有注释的方式:把"@懒惰的(真实的)"后@件等。做单身初始化懒惰和避免的实例,要求范围内的豆子太早。