2013-12-12 27 views
14

Nelle nostre applicazioni Web Spring, utilizziamo i profili bean Spring per differenziare tre scenari: sviluppo, integrazione e produzione. Li usiamo per connetterci a diversi database o impostare altre costanti.Test di integrazione della molla con profilo

L'utilizzo dei profili bean Spring funziona molto bene per la modifica dell'ambiente dell'app Web.

Il problema che abbiamo è quando il nostro codice di prova deve cambiare per l'ambiente. In questi casi, il test di integrazione carica il contesto dell'applicazione dell'app Web. In questo modo non è necessario ridefinire connessioni, costanti, ecc. (Applicando il principio DRY).

Abbiamo impostato i nostri test di integrazione come segue.

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = ["classpath:applicationContext.xml"]) 
public class MyTestIT 
{ 
    @Autowired 
    @Qualifier("myRemoteURL") // a value from the web-app's applicationContext.xml 
    private String remoteURL; 
    ... 
} 

posso farlo funzionare localmente utilizzando @ActiveProfiles, ma questo è hard-coded e provoca i nostri test a fallire sul server di build.

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = ["classpath:applicationContext.xml"]) 
@ActiveProfiles("development") 
public class MyTestIT 
{ ... } 

Ho anche provato ad utilizzare il @WebAppConfiguration sperando che potesse in qualche modo importare la proprietà spring.profiles.active da Maven, ma questo non funziona.

Un'altra nota, dobbiamo anche configurare il nostro codice in modo che gli sviluppatori possano eseguire l'app Web e quindi eseguire i test utilizzando il test runner di IntelliJ (o un altro IDE). Questo è molto più facile per il debug dei test di integrazione.

risposta

29

Come altri hanno già fatto notare, è possibile scegliere di utilizzare Maven per impostare la proprietà di sistema spring.profiles.active, assicurandosi che non sia per utilizzare @ActiveProfiles, ma questo non è conveniente per i test eseguiti all'interno dell'IDE.

Per un metodo programmatico per impostare i profili attivi, sono disponibili alcune opzioni.

  1. Primavera 3.1: scrivere un personalizzato ContextLoader che prepara il contesto impostando profili attivi nel contesto del Environment.
  2. Spring 3.2: un'opzione personalizzata ContextLoader rimane un'opzione, ma una scelta migliore è implementare un ApplicationContextInitializer e configurarlo tramite l'attributo initializers di @ContextConfiguration. L'inizializzatore personalizzato può configurare Environment impostando i profili attivi al livello di programmazione.
  3. Spring 4.0: le opzioni di cui sopra esistono ancora; tuttavia, a partire da Spring Framework 4.0 c'è una nuova API dedicata ActiveProfilesResolver esattamente per questo scopo: determinare a livello di programmazione il set di profili attivi da utilizzare in un test. Un ActiveProfilesResolver può essere registrato tramite l'attributo resolver di @ActiveProfiles.

saluti,

Sam (autore della Spring Framework TestContext)

+0

sto usando Primavera 3.2 e item # 2 opere molto bene per questo. Ho impostato il mio 'ApplicationContextInitializer' per chiamare' configurableApplicationContext.getEnvironment(). SetDefaultProfiles ("sviluppo"); 'che esegue il profilo di sviluppo quando eseguo i test tramite IntelliJ. –

+0

C'è un esempio su come usare 'ActiveProfilesResolver'? Non so davvero come usarlo – daydreamer

+1

Sì, c'è un esempio di come usare un 'ActiveProfilesResolver 'personalizzato nel [capitolo Test] (http://docs.spring.io/spring/docs/current/spring-framework -reference/html/testing.html # testcontext-ctx-management-env-profiles-ActiveProfilesResolver) del manuale di riferimento del framework di primavera. –

3

Se si desidera evitare l'hard-coding del profilo, è possibile utilizzare system propertyspring.profiles.active e impostarlo in base a ciò che è necessario in quel particolare ambiente, ad es. abbiamo i profili "dev", "stage" e "prod" per i nostri diversi ambienti; inoltre abbiamo i profili "test", "test-local" e "test-server" per i nostri test.

Ricordare che è possibile avere più di un profilo in quella proprietà di sistema utilizzando un elenco di valori separati da virgole, ad es. "Test, test-qa".

È possibile specificare le proprietà del sistema in un progetto Maven nel maven surefire plugin o di passaggio così:

mvn -DargLine="-DpropertyName=propertyValue" 
0

Come accennato @ElderMael è possibile utilizzare la proprietà argLine di Maven plug infallibile. Spesso quando ho bisogno di eseguire tutti i test con diversi profili Spring specifici, definisco un profilo Maven addizionale. Esempio:

<profiles> 
    <profile> 
     <id>foo</id> 
     <dependencies> 
      <!-- additional dependencies if needed, i.e. database drivers -> 
     </dependencies> 
     <build> 
      <plugins> 
       <plugin> 
        <groupId>org.apache.maven.plugins</groupId> 
        <artifactId>maven-surefire-plugin</artifactId> 
        <configuration> 
         <argLine>-Dspring.profiles.active=foo</argLine> 
        </configuration> 
       </plugin> 
      </plugins> 
     </build> 
    </profile> 
</profiles> 

Con questo approccio si potrebbe facilmente eseguire tutti i test con profilo attivato da Maven comando:

mvn clean test -Pfoo 

L'annotazione @ActiveProfile è buono, ma a volte abbiamo bisogno di eseguire tutti i test con attivazione profili specifici e con parametri codificati @ActiveProfile è un problema.

Ad esempio: per impostazione predefinita test di integrazione con db in memoria H2, ma a volte si desidera eseguire test sul database "reale". È possibile definire quel profilo maven aggiuntivo e definire il lavoro Jenkins. Con SpringBoot puoi anche aggiungere proprietà aggiuntive a test/risorse con nome application-foo.yml (o proprietà) e queste proprietà verranno prese in considerazione.

10

ho avuto un problema simile: Volevo correre tutti i miei test di integrazione con un profilo predefinito, ma consentire a un utente di sovrascrivere con un profilo che ha rappresentato un ambiente diverso o il sapore anche db senza dover cambiare il valore @ActiveProfiles . Questo è fattibile se si utilizza Spring 4.1+ con un ActiveProfilesResolver personalizzato.

Questo esempio risolutore cerca una proprietà di sistema, spring.profiles.active, e se non esiste, delegherà al risolutore di default che utilizza semplicemente l'annotazione @ActiveProfiles.

public class SystemPropertyActiveProfileResolver implements ActiveProfilesResolver { 

private final DefaultActiveProfilesResolver defaultActiveProfilesResolver = new DefaultActiveProfilesResolver(); 

@Override 
public String[] resolve(Class<?> testClass) { 

    if(System.getProperties().containsKey("spring.profiles.active")) { 

     final String profiles = System.getProperty("spring.profiles.active"); 
     return profiles.split("\\s*,\\s*"); 

    } else { 

     return defaultActiveProfilesResolver.resolve(testClass); 
    } 
} 

}

e nelle vostre classi di test, si può usare in questo modo:

@RunWith(SpringJUnit4ClassRunner.class) 
@ActiveProfiles(profiles={"h2","xyz"}, 
resolver=SystemPropertyActiveProfileResolver.class) 
public class MyTest { } 

Ovviamente si può utilizzare altri metodi oltre a controllare l'esistenza di una proprietà di sistema per impostare i profili attivi. Spero che questo aiuti qualcuno.

-1

ci sono molti aspetti di questo problema. nel mio caso, una semplice aggiunta a build.gradle già aiutato:

test { systemProperties = System.properties } 
Problemi correlati