如何让 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”) @可配置 公共类 UserDetailsS​​erviceImplIntegrationTest @自动连线 UserDataOnDemand dod; // @Autowired 不适用于 applicationContext-security.xml 中的这个 bean 用户详细信息服务用户详细信息服务; @前 公共无效设置() dod.init(); // 自动装配问题的解决方法 userDetailsS​​ervice = (UserDetailsS​​ervice)ctx.getBean("userDetailsS​​ervice"); @测试 公共无效 testLoadUser() UserDetails ud = userDetailsS​​ervice.loadUserByUsername("david@somewhere.co.za"); Assert.assertEquals("david@somewhere.co.za", ud.getUsername());

我正在使用 Spring 3.0.3。

这是当我取消注释 UserDetailsS​​ervice 的 @Autowired 行时的堆栈跟踪:

org.springframework.beans.factory.BeanCreationException:创建名为“za.co.acme.app.security.UserDetailsS​​erviceImplIntegrationTest”的bean时出错:注入自动装配的依赖项失败;嵌套异常是 org.springframework.beans.factory.BeanCreationException:无法自动装配字段:org.springframework.security.core.userdetails.UserDetailsS​​ervice za.co.acme.app.security.UserDetailsS​​erviceImplIntegrationTest.userDetailsS​​ervice;嵌套异常是 org.springframework.beans.factory.NoSuchBeanDefinitionException:没有为依赖项找到类型为 [org.springframework.security.core.userdetails.UserDetailsS​​ervice] 的匹配 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.UserDetailsS​​erviceImplIntegrationTest.(UserDetailsS​​erviceImplIntegrationTest.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>

UserDetailsS​​erviceImplIntegrationTest.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”?

【讨论】:

嗯,手动查找 UserDetailsS​​ervice bean 的事实表明上下文文件实际上正在加载。它只是由于某种原因无法工作的自动装配部分。【参考方案6】:

你的 xml 中 userDetailsService 的 bean 的名称是什么?您可能需要使用 bean 名称添加 @Qualifier 注释,然后在上下文中放置 &lt;qualifier&gt; 标记。

看看Spring's documentation的话题。

【讨论】:

我确实尝试过,也尝试过使用@Resource,但没有任何运气。我只有一个 UserDetailsS​​ervice bean,所以按类型也应该可以工作。错误消息表明找不到具有正确类型的 bean。

以上是关于如何让 Spring 使用多个上下文自动装配集成测试类?的主要内容,如果未能解决你的问题,请参考以下文章

Spring之Bean的自动装配

Spring中如何混用XML与Java装配方式

Spring TestRestTemplate 未正确自动装配

Spring框架学习:@Qualifier实现高级装配

spring boot:如何配置自动装配的 WebTestClient

如何在 spring-servlet.xml 中自动装配 crud 存储库?