wake-up-neo.com

Spring-Anwendungskontext innerhalb einer Testmethode neu laden oder aktualisieren?

Ich muss die in meinem applicationContext aktiven Spring-Profile innerhalb einer einzelnen Methode meiner Testklasse ändern und dazu eine Codezeile ausführen, bevor ich den Wettbewerb aktualisiere, da ich einen ProfileResolver verwende. Ich habe Folgendes versucht:

@WebAppConfiguration
@ContextConfiguration(locations = {"/web/WEB-INF/spring.xml"})
@ActiveProfiles(resolver = BaseActiveProfilesResolverTest.class)
public class ControllerTest extends AbstractTestNGSpringContextTests {
    @Test
    public void test() throws Exception {
        codeToSetActiveProfiles(...);
        ((ConfigurableApplicationContext)this.applicationContext).refresh();
        ... tests here ...
        codeToSetActiveProfiles(... back to prior profiles ...);
        ... ideally refresh/reload the context for future tests
    }
}

Aber ich bekomme:

Java.lang.IllegalStateException: GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once

DirtiesContext funktioniert bei mir nicht, da es NACH der Ausführung von Klassen/Methoden ausgeführt wird, und ich muss ohnehin eine Codezeile ausführen, bevor ich das Aktualisieren/Neuladen ausführen kann.

Irgendwelche Vorschläge? Ich habe versucht, einen Blick auf die Listener/Hooks zu werfen, die ausgeführt werden, aber ich habe keinen offensichtlichen Ort gefunden, an dem ich mich einfügen könnte, um dieses Verhalten zu erreichen.

10
David E

Die programmgesteuerte Aktualisierung einer ApplicationContext wird vom Spring TestContext Framework nicht explizit unterstützt. Außerdem ist nicht beabsichtigt, dass eine Testmethode einen Kontext aktualisiert.

Daher würde ich Ihnen empfehlen, die Notwendigkeit einer Aktualisierung zu überprüfen, und es sollten Alternativen in Betracht gezogen werden, z. B. Testmethoden, die einen anderen Satz aktiver Profile erfordern, in einer dedizierten Testklasse. 

Zusammenfassend unterstützt @ActiveProfiles deklarativ configuration (über value- und profiles-Attribute) und programmatic configuration (über das resolver-Attribut) der aktiven Profile für Tests, jedoch nur auf Testklassenebene ( nicht auf der Methodenebene). Eine andere Möglichkeit ist, eine ApplicationContextInitializer zu implementieren und diese über @ContextConfiguration(initializers=...) zu konfigurieren.

Die einzige Möglichkeit, die ApplicationContextbefore zu beeinflussen, die aktualisiert wird, besteht darin, eine SmartContextLoader zu implementieren oder eine der bereitgestellten Klassen zu erweitern und sie über @ContextConfiguration(loader=...) zu konfigurieren. Zum Beispiel erlaubt AbstractGenericContextLoader.customizeContext() "die durch den loader erstellte GenericApplicationContext anzupassen. after bean - Definitionen wurden in den Kontext geladen, aber before der Kontext wird aktualisiert."

Freundliche Grüße,

Sam (Autor des Spring TestContext Framework)

12
Sam Brannen

Es gibt einen netten kleinen Hack, um eine Kontextaktualisierung auszulösen - um org.springframework.cloud.context.refresh.ContextRefresher Zu verwenden.

Ich bin nicht zu 100% sicher, ob diese Methode zu Ihnen passt: benötigt eine spring-cloud-context - Abhängigkeit. Dies kann jedoch nur als test - Abhängigkeit hinzugefügt werden und nicht in den Produktionsklassenpfad gelangen.

Um diese Aktualisierung zu verwenden, müssen Sie auch die Konfiguration org.springframework.cloud.autoconfigure.RefreshAutoConfiguration Importieren, die Ihrem RefreshScope-Bereich einen applicationContext hinzufügt, der tatsächlich die Arbeit unter der Haube erledigt.

Ändern Sie den Test also wie folgt:

import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration;
import org.springframework.cloud.context.refresh.ContextRefresher;    
// your other imports


@WebAppConfiguration
@ContextConfiguration(locations = {"/web/WEB-INF/spring.xml"}, classes = RefreshAutoConfiguration.class)
@ActiveProfiles(resolver = BaseActiveProfilesResolverTest.class)
public class ControllerTest extends AbstractTestNGSpringContextTests {

    @Autowired
    private ContextRefresher contextRefresher;

    @Test
    public void test() throws Exception {
        // doSmth before
        contextRefresher.refresh();
        // context is refreshed - continue testing
    }

}
0
Ivan Pronin

Nicht alle Anwendungskontexte unterstützen mehrere refresh. Gemäß javadoc für AbstractRefreshableApplicationContext akzeptieren nur Unterklassen davon oder von AbstractRefreshableWebApplicationContextrefresh mehr als einmal ... und GenericApplicationContext in keiner von ihnen.

Sie sollten eine andere Klasse für Ihre ApplicationContext verwenden, um die heiße Aktualisierung zu unterstützen.

Bearbeiten:

Wenn Sie die @ContextConfiguration-Annotation verwenden, sollten Sie eine benutzerdefinierte ContextLoader- oder SmartContextLoader-Implementierung verwenden, um spring zu zwingen, eine weniger dumme ApplicationContext zu verwenden. Aber ich habe nie einen sauberen und ordentlichen Weg dazu gefunden. Wenn ich also eine XmlWebApplicationContext in meinen Testklassen brauche, verwende ich nicht @ContextConfiguration, sondern erstelle und aktualisiere meinen Kontext per Hand in einer @Before-Methode oder zu Beginn eines Tests.

Ich weiß, dass dies Ihre Frage nicht wirklich beantwortet, aber Sie können es als Problemumgehung ansehen.

0
Serge Ballesta