2010-08-05 2 views
13

Uno dei miei test di integrazione utilizza più file di contesto Spring. Sembra che Spring produca solo autowires in bean dal primo contesto e non il secondo. Qualcuno sa cosa sto facendo male o come risolvere il problema?Come ottenere la classe di test di integrazione autowire di Spring utilizzando più contesti?

 
@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("[email protected]"); 
     Assert.assertEquals("[email protected]", ud.getUsername()); 
    } 
} 

Sto usando Spring 3.0.3.

Ecco la traccia dello stack quando togliere il commento alla linea di @Autowired per 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) 

Il fagiolo è sicuramente lì dal momento che i "per nome" opere di ricerca, ed è del tipo corretto.

+0

qualcosa nei registri? – Bozho

+0

Ho aggiunto una traccia dello stack –

risposta

0

Qual è il nome del bean per userDetailsService nel tuo xml? Potrebbe essere necessario aggiungere un'annotazione @Qualifier con il nome del bean e quindi inserire un tag <qualifier> nel contesto.

Dai uno sguardo allo Spring's documentation sull'argomento.

+0

L'ho provato e ho anche provato a utilizzare @Resource senza fortuna. Ho solo un bean UserDetailsService, quindi per tipo dovrebbe funzionare anche. I messaggi di errore indicano che nessun bean con il tipo corretto potrebbe essere trovato. –

7

Una soluzione alternativa consiste nel creare un nuovo singolo file di configurazione (chiamiamolo "test-configuration.xml") che include sia applicationContext.xml che applicationContext-security.xml. Quindi puoi usare queste configurazioni all'interno dei tuoi test.

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 { 
... 
} 
3

Ho una configurazione simile e che sta funzionando bene per me.

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

La mia ipotesi è che il problema sia nella configurazione del progetto. Usi Eclipse? Carica i file di contesto dalla cartella/bin o da una cartella/src? Hai escluso "applicationContext-security.xml" dal build?

+0

Bene il fatto che la ricerca manuale del bean UserDetailsService funzioni indica che i file di contesto sono in effetti caricati ok. È solo la parte di autowiring che non funziona per qualche motivo. –

+0

Grazie, questo ha funzionato bene per me. – Mythul

1

È necessario dire a Spring di agire su quelle annotazioni. Nel file di contesto pertinente dovresti aggiungere quanto segue:

<context:annotation-config/> 

Ora eseguirà la scansione di quelle annotazioni. Vedere la documentazione di primavera sulla Annotation-based configuration

Per limitare il numero di classi di cui ha bisogno per eseguire la scansione in modo da non inutilmente la scansione di pacchetti senza autowiring, aggiungere questo:

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

Vedere la documentazione per Auto-detecting components per maggiori informazioni su così come i namespace XML che dovrai aggiungere per fare riferimento a quei tag.

0

Ho gli stessi problemi. Sembra che ci sia un proxy UserDataOnDemand invece del reale UserDataOnDemand.

4

Ho avuto lo stesso problema, la soluzione risolta il mio problema è passare il bean esporre tramite Interface. (io.e) Il tuo Bean Type di riferimento dovrebbe essere un'interfaccia invece della sua classe di implementazione

Nel tuo caso modificare il riferimento di Classe UserDetailsService concreto con la sua interfaccia.

Per esempio:

@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 

} 

NOTA: So che questo non sarà una soluzione ragionevole, ma basta dare una prova, mi sono preoccupato molto a causa di questo stesso errore e, infine, ha cambiato il mio riferimento e ha funzionato bene Spero che risolva il tuo problema.