17 votes

Comment faire en sorte que Spring autowire la classe de test d'intégration en utilisant plusieurs contextes ?

Un de mes tests d'intégration utilise plusieurs fichiers de contexte Spring. Il semble que Spring n'intègre automatiquement que les beans du premier contexte et non du second. Quelqu'un sait-il ce que je fais de mal ou comment contourner le problème ?

@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());
    }
}

J'utilise Spring 3.0.3.

Voici la trace de la pile lorsque je décompose la ligne @Autowired pour UserDetailsService :

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)

Le haricot est bien présent puisque la recherche "par nom" fonctionne et qu'il est du bon type.

7voto

Ralph Points 42744

Une solution consiste à créer un nouveau fichier de configuration unique (appelons-le "test-configuration.xml") qui comprend les fichiers applicationContext.xml et applicationContext-security.xml. Vous pouvez ensuite utiliser ces configurations dans vos tests.

test-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 :

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

4voto

J'ai une configuration similaire et cela fonctionne bien pour moi.

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

Je pense que le problème se situe dans la configuration de votre projet. Utilisez-vous Eclipse ? Charge-t-il les fichiers contextuels depuis le dossier /bin ou depuis un dossier /src ? Avez-vous exclu "applicationContext-security.xml" de la construction ?

4voto

omega Points 542

J'ai eu le même problème, la solution qui a réglé mon problème est de changer l'exposition du haricot par l'interface. (i.e.) Votre type de bean de référence devrait être un Interface au lieu de sa classe d'implémentation

Dans votre cas, changez la classe concrète UserDetailsService référence avec son interface.

Par exemple :

@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 : Je sais que ce ne sera pas une solution raisonnable, mais essayez, je me suis beaucoup inquiété à cause de cette même erreur et j'ai finalement changé ma référence et ça a marché. J'espère que cela résoudra votre problème.

1voto

Lyle Points 1257

Vous devez dire à Spring d'agir sur ces annotations. Dans le fichier contextuel approprié, vous devez ajouter ce qui suit :

<context:annotation-config/>

Maintenant, il va rechercher ces annotations. Voir la documentation de Spring sur Configuration basée sur les annotations

Pour limiter le nombre de classes qu'il doit analyser afin de ne pas analyser inutilement les paquets sans câblage automatique, ajoutez ceci :

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

Voir les documents relatifs à Composants à autodétection pour en savoir plus à ce sujet, ainsi que sur les espaces de noms XML que vous devrez ajouter pour référencer ces balises.

0voto

Noel M Points 6263

Quel est le nom du haricot pour userDetailsService dans votre xml ? Vous pourriez avoir besoin d'ajouter un @Qualifier avec le nom du haricot, puis en mettant une annotation <qualifier> dans le contexte.

Jetez un coup d'œil à La documentation de Spring sur le sujet.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X