如何让 Spring 使用多个上下文自动装配集成测试类?
Posted
技术标签:
【中文标题】如何让 Spring 使用多个上下文自动装配集成测试类?【英文标题】:How to get Spring to autowire integration test class using multiple contexts? 【发布时间】:2011-03-25 17:26:07 【问题描述】:我的一个集成测试使用多个 Spring 上下文文件。似乎 Spring 仅从第一个上下文而不是第二个上下文中自动装配 bean。有谁知道我做错了什么或如何解决这个问题?
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(位置 = “类路径:/META-INF/spring/applicationContext.xml”, “类路径:/META-INF/spring/applicationContext-security.xml”) @可配置 公共类 UserDetailsServiceImplIntegrationTest @自动连线 UserDataOnDemand dod; // @Autowired 不适用于 applicationContext-security.xml 中的这个 bean 用户详细信息服务用户详细信息服务; @前 公共无效设置() dod.init(); // 自动装配问题的解决方法 userDetailsService = (UserDetailsService)ctx.getBean("userDetailsService"); @测试 公共无效 testLoadUser() UserDetails ud = userDetailsService.loadUserByUsername("david@somewhere.co.za"); Assert.assertEquals("david@somewhere.co.za", ud.getUsername());我正在使用 Spring 3.0.3。
这是当我取消注释 UserDetailsService 的 @Autowired 行时的堆栈跟踪:
org.springframework.beans.factory.BeanCreationException:创建名为“za.co.acme.app.security.UserDetailsServiceImplIntegrationTest”的bean时出错:注入自动装配的依赖项失败;嵌套异常是 org.springframework.beans.factory.BeanCreationException:无法自动装配字段:org.springframework.security.core.userdetails.UserDetailsService za.co.acme.app.security.UserDetailsServiceImplIntegrationTest.userDetailsService;嵌套异常是 org.springframework.beans.factory.NoSuchBeanDefinitionException:没有为依赖项找到类型为 [org.springframework.security.core.userdetails.UserDetailsService] 的匹配 bean:预计至少有 1 个 bean 有资格作为此依赖项的自动装配候选者。依赖注解:@org.springframework.beans.factory.annotation.Autowired(required=true) 在 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:286) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1064) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:374) 在 org.springframework.beans.factory.wiring.BeanConfigurerSupport.configureBean(BeanConfigurerSupport.java:140) 在 org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect.configureBean(AnnotationBeanConfigurerAspect.aj:59) 在 org.springframework.beans.factory.aspectj.AbstractDependencyInjectionAspect.ajc$afterReturning$org_springframework_beans_factory_aspectj_AbstractDependencyInjectionAspect$2$1ea6722c(AbstractDependencyInjectionAspect.aj:89) 在 za.co.acme.app.security.UserDetailsServiceImplIntegrationTest.(UserDetailsServiceImplIntegrationTest.java:25) 在 sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 在 sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) 在 sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) 在 java.lang.reflect.Constructor.newInstance(Constructor.java:513) 在 org.junit.runners.BlockJUnit4ClassRunner.createTest(BlockJUnit4ClassRunner.java:202)该 bean 肯定存在,因为“按名称”查找有效,并且它的类型正确。
【问题讨论】:
【参考方案1】:一种解决方法是创建一个新的单个配置文件(我们称之为“test-configuration.xml”),其中包括 applicationContext.xml 和 applicationContext-security.xml。然后您可以在测试中使用这些配置。
测试配置.xml:
<?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-3.0.xsd">
<import resource="classpath:/META-INF/spring/applicationContext.xml"/>
<import resource="classpath:/META-INF/spring/applicationContext-security.xml"/>
</beans>
UserDetailsServiceImplIntegrationTest.java:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/test-configuration.xml")
@Configurable
public class UserDetailsServiceImplIntegrationTest
...
【讨论】:
【参考方案2】:我有同样的问题,解决我的问题的解决方案是通过接口切换 bean 暴露。 (即)您的参考 Bean Type 应该是 Interface 而不是它的实现类
在您的情况下,使用其接口更改具体的 Class UserDetailsService
引用。
例如:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations =
"classpath:/META-INF/spring/applicationContext.xml",
"classpath:/META-INF/spring/applicationContext-security.xml")
@Configurable
public class UserDetailsServiceImplIntegrationTest
//modified code
@Autowired
IUserDetailsService userDetailsService;
//your test cases follows
注意:我知道这不是一个明智的解决方案,但请尝试一下,因为同样的错误,我很担心,最后更改了我的参考,它工作正常。希望它能解决您的问题。
【讨论】:
【参考方案3】:我也有同样的问题。好像有一个代理 UserDataOnDemand 而不是真正的 UserDataOnDemand 。
【讨论】:
【参考方案4】:您需要告诉 Spring 对这些注释采取行动。在相关的上下文文件中,您应该添加以下内容:
<context:annotation-config/>
现在它将扫描这些注释。请参阅 Annotation-based configuration 上的 Spring 文档
要限制它需要扫描的类的数量,这样您就不会在没有自动装配的情况下不必要地扫描包,添加以下内容:
<context:component-scan base-package="org.example"/>
请参阅Auto-detecting components 的文档以了解更多信息,以及您需要添加以引用这些标签的 XML 命名空间。
【讨论】:
【参考方案5】:我有类似的设置,对我来说效果很好。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:/applicationContext-struts.xml", "classpath:/applicationContext.xml" )
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
@Transactional
public abstract class BaseTests
我的猜测是问题出在您的项目设置中。你使用 Eclipse 吗?它是从 /bin 文件夹还是从 /src 文件夹加载上下文文件?您是否从构建中排除了“applicationContext-security.xml”?
【讨论】:
嗯,手动查找 UserDetailsService bean 的事实表明上下文文件实际上正在加载。它只是由于某种原因无法工作的自动装配部分。【参考方案6】:你的 xml 中 userDetailsService
的 bean 的名称是什么?您可能需要使用 bean 名称添加 @Qualifier
注释,然后在上下文中放置 <qualifier>
标记。
看看Spring's documentation的话题。
【讨论】:
我确实尝试过,也尝试过使用@Resource,但没有任何运气。我只有一个 UserDetailsService bean,所以按类型也应该可以工作。错误消息表明找不到具有正确类型的 bean。以上是关于如何让 Spring 使用多个上下文自动装配集成测试类?的主要内容,如果未能解决你的问题,请参考以下文章
Spring TestRestTemplate 未正确自动装配