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.
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 ApplicationContext
before 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)
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
}
}
Nicht alle Anwendungskontexte unterstützen mehrere refresh
. Gemäß javadoc für AbstractRefreshableApplicationContext
akzeptieren nur Unterklassen davon oder von AbstractRefreshableWebApplicationContext
refresh
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.