简体   繁体   English

如何让Spring使用多个上下文自动装配集成测试类?

[英]How to get Spring to autowire integration test class using multiple contexts?

One of my integration tests uses multiple Spring context files. 我的一个集成测试使用多个Spring上下文文件。 It seems that Spring only autowires in beans from the first context and not the second. 似乎Spring只在第一个上下文而不是第二个上下文中自动装配bean。 Does anyone know what I am doing wrong or how to work around the problem? 有谁知道我做错了什么或如何解决这个问题?

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
        "classpath:/META-INF/spring/applicationContext.xml",
        "classpath:/META-INF/spring/applicationContext-security.xml"})
@Configurable
public class UserDetailsServiceImplIntegrationTest {

    @Autowired
    UserDataOnDemand dod;
    // @Autowired does not work for this bean from applicationContext-security.xml
    UserDetailsService userDetailsService;

    @Before
    public void setup() {
        dod.init();
        // workaround for autowiring problem
        userDetailsService = (UserDetailsService)ctx.getBean("userDetailsService");
    }

    @Test
    public void testLoadUser() {
        UserDetails ud = userDetailsService.loadUserByUsername("david@somewhere.co.za");
        Assert.assertEquals("david@somewhere.co.za", ud.getUsername());
    }
}

I am using Spring 3.0.3. 我正在使用Spring 3.0.3。

Here is the stack trace when I uncomment the @Autowired line for UserDetailsService: 当我取消注释UserDetailsS​​ervice的@Autowired行时,这是堆栈跟踪:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'za.co.acme.app.security.UserDetailsServiceImplIntegrationTest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.springframework.security.core.userdetails.UserDetailsService za.co.acme.app.security.UserDetailsServiceImplIntegrationTest.userDetailsService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [org.springframework.security.core.userdetails.UserDetailsService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:286)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1064)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:374)
    at org.springframework.beans.factory.wiring.BeanConfigurerSupport.configureBean(BeanConfigurerSupport.java:140)
    at org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect.configureBean(AnnotationBeanConfigurerAspect.aj:59)
    at org.springframework.beans.factory.aspectj.AbstractDependencyInjectionAspect.ajc$afterReturning$org_springframework_beans_factory_aspectj_AbstractDependencyInjectionAspect$2$1ea6722c(AbstractDependencyInjectionAspect.aj:89)
    at za.co.acme.app.security.UserDetailsServiceImplIntegrationTest.(UserDetailsServiceImplIntegrationTest.java:25)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at org.junit.runners.BlockJUnit4ClassRunner.createTest(BlockJUnit4ClassRunner.java:202)

The bean is definitely there since the "by name" lookup works, and it is of the correct type. 由于“按名称”查找起作用,bean肯定存在,并且它的类型正确。

A workaround is to create a new single configuration file (let's call it "test-configuration.xml") which is including the both applicationContext.xml and applicationContext-security.xml. 解决方法是创建一个新的单个配置文件(我们称之为“test-configuration.xml”),该文件包括applicationContext.xml和applicationContext-security.xml。 Then you can use these configurations within your tests. 然后,您可以在测试中使用这些配置。

test-configuration.xml: 测试-configuration.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: UserDetailsS​​erviceImplIntegrationTest.java:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/test-configuration.xml")
@Configurable
public class UserDetailsServiceImplIntegrationTest {
...
}

I had the same problem, the solution fixed my problem is switch the bean expose through Interface. 我有同样的问题,解决方案修复我的问题是通过接口切换bean暴露。 (ie) Your reference Bean Type should be a Interface instead of its implementation class (即)您的引用Bean Type应该是Interface而不是它的实现类

In your case change the concrete Class UserDetailsService reference with its interface. 在您的情况下,使用其接口更改具体的Class UserDetailsService引用。

For Example: 例如:

@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

}

NOTE: I know this wont be a sensible solution, But just give a try, I worried lot because of this same error and finally changed my reference and it worked fine. 注意:我知道这不是一个明智的解决方案,但只是试一试,我担心很多因为同样的错误,最后改变了我的参考,它工作正常。 Hope it would resolve your issue. 希望它能解决你的问题。

I have a similar setup and it's working fine for me. 我有类似的设置,它对我来说很好。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/applicationContext-struts.xml", "classpath:/applicationContext.xml" })
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
@Transactional
public abstract class BaseTests {

My guess is that the problem is in the setup of your project. 我的猜测是问题出在你的项目设置中。 Do you use Eclipse? 你用Eclipse吗? Does it load the context files from the /bin folder or from a /src folder? 它是从/ bin文件夹还是从/ src文件夹加载上下文文件? Did you exclude "applicationContext-security.xml" from the build? 您是否从构建中排除了“applicationContext-security.xml”?

You need to tell Spring to act on those annotations. 你需要告诉Spring对这些注释采取行动。 In the relevant context file you should add the following: 在相关的上下文文件中,您应添加以下内容:

<context:annotation-config/>

Now it'll scan for those annotations. 现在它将扫描那些注释。 See the Spring documentation on Annotation-based configuration 请参阅有关基于注释的配置的Spring文档

To limit the number of classes it needs to scan so you don't needlessly scan packages with no autowiring, add this: 要限制它需要扫描的类的数量,以便您不必不必要地扫描没有自动装配的包,请添加以下内容:

<context:component-scan base-package="org.example"/>

See the docs for Auto-detecting components for more on that, as well as the XML namespaces you'll need to add to reference those tags. 有关详细信息,请参阅自动检测组件的文档,以及为引用这些标记而需要添加的XML命名空间。

我有同样的问题。似乎有一个代理UserDataOnDemand而不是真正的UserDataOnDemand。

What is the name of the bean for userDetailsService in your xml? xml中userDetailsService的bean名称是什么? You might need to add a @Qualifier annotation with the bean name, and then putting a <qualifier> tag in the context. 您可能需要使用bean名称添加@Qualifier批注,然后在上下文中放置<qualifier>标记。

Take a look at Spring's documentation on the topic. 看一下Spring关于该主题的文档

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM